업데이트:

카테고리:

/

태그: , , , ,

컬렉션

코틀린에는 2가지 컬렉션이 존재

  1. 특정 데이터 타입의 요소를 저장하는 클래스
    • Array: 같은 타입의 요소를 저장함
  2. 다른 타입의 요소를 저장하는 클래스
    • arrayOf: 모든 타입을 저장함
  3. 변경 불가능한 클래스
    • listOf: arrayOf와 비슷하지만 더 많은 메서드가 있고 크기를 쉽게 조정가능
    • setOf: 중복된 값이 없게 함
    • mapOf: key-value 페어로 이루어짐

배열

미리 타입값을 지정하지 않아도 타입 추론으로 코틀린 내부에서 자동으로 타입이 지정된다.
배열은 그냥 출력하게 되면 주소값이 나오게 되므로 contentToString()을 통해 배열의 값을 문자로 변환 후 출력해야 한다.

contentToString은 이름만 알려주므로 자세하게 알고 싶다면 index로 접근해야한다.
indicies는 객체의 인덱스 번호를 알려주는 메서드이다.

fun main(){
  // val numbers:IntArray = intArrayOf(1, 2, 3, 4, 5, 6)
  val numbers = arrayOf(1, 2, 3, 4, 5, 6) 
  print(numbers.contentToString()) 

  // 배열 값 변경
  numbers[0] = 6
  numbers[1] = 5
  numbers[4] = 2
  numbers[5] = 1

  // 원하는 데이터 타입으로 배열을 만들 수 있다.
  val fruits = arrayOf(Fruit("Apple", 2.5), Fruit("Grape", 3.3))

  // 객체 값이 하나씩 fruit에 들어간다.
  for (fruit in fruits){
    print(" ${fruit.name}")
  }

  // 전체 fruits의 인덱스 만큼 index가 순서대로 들어간다.
  for(index in fruits.indicies){
    print("${fruits[index].name} is in index $index")
  }
}

data class Fruit(val name: String, val price:Double)

리스트(listOf)

어떠한 데이터 타입도 담을 수 있다.

  • llstOf: 변경불가한 리스트, 어떤 데이터든 담을 수 있다.
  • mutableListOf: 변경가능한 리스트, 들어갈 데이터 타입을 미리 지정해야 한다.
    fun main() {
    val months = listOf("Jan", "Feb", "Mar")
    val anyTypes = listOf(1, 2, 3, true, false, "String")
    
    // list는 immutable한 배열이므로 toMutable을 통해 변경 가능하도록 바꾼다.
    val addtionalMonths = months.toMutablList()
    val newMonths = arrayOf("Apr", "May", "Jun")
    additionalMonths.addAll(newMonths)
    additionalMonths.add("Jul")
    
    val days = mutableListOf<String>("Mon", "Tue", "Wed")
    days.add("Thu")
    // removeAt : 인덱스를 통해 삭제
    days.removeAt(3)
      
    // removeAll : 특정 값만 리스트에서 제거
    val removeList = mutableListOf<String>("Mon", "Wed")
    days.removeAll(removeList)
    }
    

집합(Set)

중복되는 값을 제거하고 순서가 없다.

  • setOf: 변경불가한 집합, 어떤 데이터든 담을 수 있다.
  • mutable SetOf: 변경가능한 집합, 들어갈 데이터 타입을 미리 지정해야 한다.
  • hashSetOf:
    fun main(){
    val fruits = setOf("오렌지", "사과", "포도", "사과", "망고")
    // toSortedSet : 순서대로 정렬한다.
    print(fruits.toSortedSet())
    
    val newFruits = fruits.toMutableist()
    newFruits.add("수박")
    newFruits.add("배")
    // elementAt : 특정인덱스로 접근
    newFruits.elementAt(4)
    }
    

맵(map)

  • key - value 형태로 데이터를 저장하는 컬렉션
  • key는 하나의 값만 저장 가능
  • to를 통해서 키와 밸류값을 지정
  • value는 어떤한 값으로도 가능

생성자

  • mapOf: immutable
  • mutable mapOf: mutable

      fun main(){
        val daysofTheWeek = mapOf(1 to "Monday", 2 to "Tuesday", 3 to "Wedsnesday")
    
        // key으로 value에 접근할 수 있다.
        for(key in daysOfTheWeek.keys){
          print("$key is to ${daysOfTheWeek[key]}")
        }
    
        val fruitsMap = mapOf("Favorite" to Fruit("Grape", 2.5), "OK" to Fruit("Apple", 1.0))
    
        // mutable한 객체로 변경
        val newDaysOfWeek = daysToTheWeek.toMutableMap()
        newDaysOfWeek[4] = "Thursday"
        newDaysOfWeek[5] = "Friday"
    
        // 정렬
        print(newDaysOfWeek.toSortedMap())
          
      }
    
      data class Fruit(val name: String, val price: Double)
    

ArrayLists

  • 동적 배열을 만들어준다. 그러므로 필요에 따라 크기가 늘고 줄어들 수 있음
  • 읽기 & 쓰기 둘 다 가능
  • 삽입 시퀸스 순서를 따름
  • 중복 요소 포함 가능
  • 하지만 immutable한 배열이기에 val로 생성

ArrayList 생성자

  • ArrayList<E>(): 비어 있는 배열리스트 생성
  • ArrayList(capacity: Int): 길이가 정해진 배열리스트 생성
  • ArrayList(elements: Collection<E>): 컬랙션 요소로 채울 수 있는 배열리스트 생성

Array List Function

  • add(): 특정요소를 컬랙션에 추가
  • clear(): 모든요소를 제거
  • get(): 특정 값에 대한 인덱스값의 정보를 반환
  • remove(): 특정 요소를 제거함, 만약 값이 여러개일 경우 첫번째의 값이 사라짐
  • iterator(): 배열리스트가 값을 가지고 있는 한 루프를 계속돎

람다식

  • 이름이 없는 함수
  • 선언되지 않고 곧바로 표현식으로 넘어감
  • 화살표(->)와 함께 사용
  • 고급 기능을 가진 코드를 간결하고 짧게 정리
  • 문법 : { variables(매개변수) -> lambda식 }

두 숫자를 더하는 람다함수

// 기존
fun addNumber (a: Int, b: Int){
  return a + b
}

// 람다식
val sum: (Int, Int) -> Int = {a: Int, b: Int -> a + b}
val sum = {a: Int, b: Int -> print(a + b)}

접근제한자

  • 클래스, 인터페이스, 프로퍼티를 제한하는데 사용
  • 클래스 헤더나 메서드 바디 등 여러 곳에서 사용

종류

  1. public
    • 프로젝트 어디서든 접근 가능
    • 코틀린에서 기본 제한자
    • 공개 선언은 파일 위에 선언
  2. private
    • 선언된 블록에서만 접근 가능
    • 스코프 밖으로의 접근을 막음
    • 같은 클래스나 같은 파일 안에서만 사용이 가능
  3. protected
    • 그 안의 클래스 또는 서브 클래스에 보이도록 함
    • 오버라이딩으로 변경하지 않는 이상 남아있음
    • 최상위에 선언될 수 없음, 즉 패키지는 보호 받을 수 없음
  4. internal
    • 자바에는 없는 코틀린만의 기능
    • 시행된 파일안에서만 필드가 보이드록 함
    • 모든 필드는 internal 필드로 선언됨
  5. open
    • 코틀린에서 모든 클래스는 자동으로 상속받을 수 없음
    • 상속을 사용하기 위해서는 open 키워드를 사용해야 됨
    • 오버라이딩할 변수나 함수 또한 해당 키워드를 사용해야 됨

중첩클래스 & 내부클래스

중접 클래스

  • 다른 클래스 안에 생성되어 자동으로 정적임
  • 객체를 만들지 않고, 함수와 변수를 사용 가능
  • 객체에서 프로퍼티처럼 사용이 가능함
  • 중첩 클래스는 외부 클래스의 데이터에 접근 불가
      class OuterClass{
        private var name: String = "Mr X"
        class NestedClass{
          var description: String = "code inside nested class"
          private var id: Int = 101
          fun foo() {
            // Error : 중첩 클래스에서 외부 클래스의 데이터는 접근 불가
            print("name is ${name}") 
            print("Id is ${Id}")
          }
        }
      }
    
      fun main(args:Array<String>){
        // 객체를 따로 만들지 않아도 중첩 클래스 내부에 접근 가능
        println(OuterClass.NextedClass().description) // code insie..
    
        var obj = OuterClass.NestedClass()
        obj.foo() // Id is 101
      }
    

내부 클래스

  • 키워드 inner로 다른 클래스 안에 만들어진 클래스
  • 중첩 클래스와 유사하나 큰 차이점은 인터페이스 안 또는 내부 중첩 클래스가 아닌 곳에는 선언될 수 없음
  • private이더라도 외부 클래스 데이터에 접근이 가능함
  • 외부 클래스 객체의 참조를 저장
  • 객체 생성시 ()를 통해 OuterClass에 접근해야 됨
      class OuterClass{
        private var name: String = "Mr X"
        inner class InnerClass{
          var description: String = "code inside nested class"
          private var id: Int = 101
          fun foo() {
            print("name is ${name}") 
            print("Id is ${Id}")
          }
        }
      }
    
      fun main(args:Array<String>){
        // 생성시 OuterClass도 ()로 접근해야 됨
        println(OuterClass().InnerClass().description) // code insie..
    
        var obj = OuterClass().NestedClass()
        obj.foo() // name is
      }
    

UnSafe & Safe Cast

Cast : 특정 타입을 다른 타입으로 바꾸는 것

Unsafe Cast : as

  • 어떤 떄는 변수를 캐스트하지 못하고 예외 처리됨
  • infix 연산자 as에 의해 실행됨
      fun main(args: Array<String>){
        val obj: Any? = null
        val str: String = obj as String
        // Error : null은 String으로 캐스트 불가
        println(str) 
    
        val obj: Any = 123
        // ClassCastException
        val str: String = obj as String
      }
    

    ⇒ 캐스팅되기 위해서는 변수와 소스는 항상 Nullable이어야 한다.

Safe Cast : as?

  • 한 타입으로 안전하게 캐스트하도록 도움
  • 캐스팅할 수 없을 때 예외처리가 아닌 null값을 반환
      fun main(args: Array<String>){
        val location: Any = "Kotlin"
        val safeString: String? = locatoin as? String
        val safeInt: Int? = location as? Int
        println(safeString) // Kotlin
        println(safeInt)    // null
      }
    

예외처리 - Try-Catch문

Exception

  • 프로그램의 런타임 문제
  • 프로그램 종료를 초래함
    • 저장공간 부족
    • out fo bound 배열
    • divide 0
  • 프로그램 실행에서 해당 문제를 처리하기 위해 Exception handling을 사용
  • 런타임 문제를 처리하고 프로그램의 원할한 작동하도록 함

Throwable Class

  • 예외를 던지게 함
  • 총 4개의 클래스가 존재
    1. try
      • 예외를 발생시킬수 있는 구문
      • catch, finally 중 하나는 반드시 뒤에 작성해야함
    2. catch
      • try에서 던져진 예외를 잡음
      • 예외가 없다면 실행되지 않음
    3. finally
      • 예외가 처리되든 말든 실행
      • 중요한 코드 구문을 실행하는 데 사용
    4. throw
      • 명료하게 예외를 던짐
      • 오류를 일으키기 위해 입력
      • 오류가 어디서 나는지 테스트할 때 유용

Try-Catch 구문

// 예외 처리가 없는 구문
val str = getNumber("10")
println(str) // 10

fun getNumber(strL String): Int {
  return try {
  Integer.parseInt(str)
  } catch(e:ArithmeticExption){
    0
  }
}

// 예외 처리가 있는 구문
val str = getNumber("10.5")
println(str) // 0

fun getNumber(strL String): Int {
  return try {
  Integer.parseInt(str)
  } catch(e:ArithmeticExption){
    0
  }
}

Multiple catch Block
catch를 여러개 사용하여 다양한 오류에 대처할 수 있다.

fun main(args: Array<String>){
  try{
    val a = IntArray(5)
    a[5] = 10/0
  } catch(e: ArithmeticException){
    ...
  } catch(e: ArrayIndexOutOfBoundExceptions){
    ...
    // Exception은 모든 예외처리에 반응하게 된다.
  } catch(e: Exception){
    ...
  }
}

Nested try-catch Block
코드 블록이 예외를 발생하거나 블록 내의 다른 코드가 예외를 발생시킬 때 사용

try {
  try {
    //code block
  }catch(e:SomeException) {
    // exception
  }
} catch(e: SomeException){
  // exception
}

finally Block

fun main(args: Array<String>){
  try{
    val data = 10 / 5
    println(data)
  } catch(e: NullPointerException){
    // 예외 구문을 보여준다.
    println(e)
  } finally {
    println("finally block always executes")
  }

  println("below code..")
}

throw keyword

fun main(agrs:Array<String>){
  validata(15)
  println("code after validation check...")
}

fun validata(age: Int){
  if (age < 18)
    // 정확한 오류를 던져주기 위해 사용
    throw ArithmeticException("under age")
  else
    println('eligible for drive')
}

Unchecked Exception

  • 코드 실수 때문에 던져지는 예외
  • 코드가 어떤 이유로 실행되지 않음
  • 앱이 실행되는 런타임에 확인

종류

  • ArithmeticException: 숫자를 0으로 나눈 경우
  • ArrayIndexOutOfBoundExceptions: 인덱스 값이 올바르지 않은 경우
  • SecurityException: 보안 위반, GPS 사용 시 사용할 권리를 주지 않아 접근이 불가한 경우
  • NullPointerException: null로 비어있는 객체에 접근하려 한 경우

Checked Exception

  • Throwable 클래스로 확장
  • 해당 클래스에서 예외 함수를 이용하여 예외 처리를 함

종류

  • IOException: 입력 출력 예외
  • SQLException… 등이 존재