BackEnd/Kotlin

15강. 코틀린에서 배열과 컬렉션을 다루는 방법

hanseom 2024. 3. 21. 05:00
반응형
  1. 배열(Array)
  2. 컬렉션(Collection) - List, Set, Map
  3. 컬렉션의 null 가능성
  4. Java와 함께 사용할 때 주의할 점

 

배열

  배열은 잘 사용하지 않습니다. Effective Java에도 '배열보다 리스트를 사용하라'라고 되어 있습니다.

 

  다음은 배열을 사용한 Java 코드입니다.

    int[] array = {100, 200};

    for (int i = 0; i < array.length; i++) {
      System.out.printf("%s %s", i, array[i]);
    }

 

  Kotlin으로 구현하면 다음과 같습니다.

    val array = arrayOf(100, 200)

    for (i in array.indices) {
        println("${i} ${array[i]}")
    }

    for ((idx, value) in array.withIndex()) {
        println("$idx $value")
    }
  • array.indices: 0부터 마지막 index까지의 Range입니다.
  • withIndex(): index와 value를 한 번에 가져올 수 있습니다.

 

Collection

  컬렉션을 만들어 줄 때 불변인지, 가변인지를 설정해줘야 합니다. 다음은 Kotlin의 Collection 계층 구조입니다.

  • 가변 (Mutable) 컬렉션: 컬렉션에 element를 추가, 삭제할 수 있습니다.
  • 불변 컬렉션: 컬렉션에 element를 추가, 삭제할 수 없습니다. 단, 불변 컬렉션이라도 Reference Type인 Element의 필드는 바꿀 수 있습니다.

 

List

  다음은 Java의 List 코드입니다.

  public static void main(String[] args) {
    // List
    final List<Integer> numbers = Arrays.asList(100, 200);

    // get
    System.out.println(numbers.get(0));

    // For Each
    for (int number : numbers) {
      System.out.println(number);
    }

    // for문
    for (int i = 0; i < numbers.size(); i++) {
      System.out.printf("%s %s,", i, numbers.get(i));
    }
  }

 

  Kotlin으로 구현하면 다음과 같습니다.

fun main() {
    // List
    val numbers = listOf(100, 200)
    val emptyList = emptyList<Int>() // 비어있는 리스트의 경우 타입을 명시해 주어야 합니다.

    // get
    println(numbers.get(0))
    println(numbers[0])

    // For Each
    for (number in numbers) {
        println(number)
    }

    // 전통적인 for문
    for ((index, number) in numbers.withIndex()) {
        println("$index $number")
    }
}

 

  emptyList의 경우, 타입을 추론할 수 있다면 생략 가능합니다.

fun main() {
    printNumbers(emptyList())
}

private fun printNumbers(numbers: List<Int>) {

}

 

  가변 리스트를 만들고 싶다면, listOf() 대신 mutableList()를 사용하면 됩니다.

    val mutableNumbers = mutableListOf(100, 200)
    mutableNumbers.add(300)
  • add, remove, addAll, removeAll 같은 Java에 존재하는 모든 라이브러리 기능들이 Kotlin에도 존재합니다.
  • 기본 구현체는 ArrayList이고, 기타 사용법은 Java와 동일합니다.

Note. 우선 불변 리스트를 만들고, 반드시 필요한 경우에만 가변 리스트로 바꾸어 사용합니다.

 

Set

  집합은 List와 다르게 순서가 없고, 같은 element는 하나만 존재할 수 있습니다. 자료구조적 의미만 제외하면 모든 기능이 List와 비슷합니다.

 

  다음은 Kotlin 코드입니다.

    // Set
    val setNumbers = setOf(100, 200)

    // For Each
    for (number in setNumbers) {
        println(number)
    }

    // 전통적인 for문
    for ((index, number) in numbers.withIndex()) {
        println("$index $number")
    }

 

  가변(Mutable) 집합을 만들고 싶다면, mutableSetOf()를 사용하시면 됩니다.

val setNumbers = mutableSetOf(100, 200)
  • 기본 구현체는 LinkedHashSet 입니다.

 

Map

  다음은 Map을 생성하는 Java 코드입니다.

    // JDK 8까지
    Map<Integer, String> map = new HashMap<>();
    map.put(1, "MONDAY");
    map.put(2, "TUESDAY");

    // JDK 9부터
    Map.of(1, "MONDAY", 2, "TUESDAY");

 

  Kotlin으로 구현하면 다음과 같습니다.

    val oldMap = mutableMapOf<Int, String>()
    oldMap.put(1, "MONDAY")
    oldMap[2] = "TUESDAY"

    mapOf(1 to "MONDAY", 2 to "TUESDAY")
  • 가변 Map이기 때문에 (key, value)를 넣을 수 있습니다.
  • Java처럼 put을 쓸 수도 있고, map[key] = value을 쓸 수도 있습니다.
  • mapOf(key to value)를 사용해 불변 map을 만들 수 있습니다.

 

  다음은 Java에서 Map을 활용하는 코드입니다.

    for (int key : map.keySet()) {
      System.out.println(key);
      System.out.println(map.get(key));
    }

    for (Map.Entry<Integer, String> entry : map.entrySet()) {
      System.out.println(entry.getKey());
      System.out.println(entry.getValue());
    }

 

  Kotlin으로 구현하면 다음과 같습니다.

    for (key in oldMap.keys) {
        println(key)
        println(oldMap[key])
    }

    for ((key, value) in oldMap.entries) {
        println(key)
        println(value)
    }

 

컬렉션의 null 가능성

  • List<Int?>: List에 null이 들어갈 수 있지만, List는 절대 null이 아닙니다.
  • List<Int>?: List에는 null이 들어갈 수 없지만, List는 null일 수 있습니다.
  • List<Int?>?: List에 null이 들어갈 수도 있고, List가 null일 수도 있습니다.

? 위치에 따라 null 가능성 의미가 달라지므로 차이를 잘 이해해야 합니다.

 

Java와 함께 사용할 때 주의할 점

  • Java는 읽기 전용 컬렉션과 변경 가능 컬렉션을 구분하지 않습니다.
  • Java는 nullable 타입과 non-nullable 타입을 구분하지 않습니다.
  • Kotlin 쪽의 컬렉션이 Java에서 호출되면 컬렉션 내용이 변할 수 있음을 감안해야 합니다.
  • Kotlin 쪽에서 Collections.unmodifableXXX()를 활용하면 변경 자체를 막을 수는 있습니다.
  • Kotlin에서 Java 컬렉션을 가져다 사용할 때는 플랫폼 타입을 신경써야 합니다. Java 코드를 보며 맥락을 확인하고, Java 코드를 가져오는 지점을 wrapping해서 영향 범위를 최소화하는 것이 좋습니다.

 

 

 

감사합니다.

반응형