Collection(콜렉션)은 대부분의 프로그래밍 언어에 있는 자료구조입니다. 자바의 List, Map, Set 등을 Collection이라고 합니다. Collection은 Generic으로 구현이 되어 다양한 타입과 함께 사용될 수 있습니다.
코틀린의 Collection은 기본적으로 Mutable(변할 수 없는)과 Immutable(불변의)을 별개로 지원합니다. Mutable로 생성하면 추가, 삭제가 가능하지만, Immutable로 생성하면 수정이 안됩니다.
코틀린의 콜렉션들은 아래 그림과 같은 상속 구조 갖고 있습니다.
(출처: kotlinlang.com)
이 글에서는 콜렉션을 한번씩 사용해보았다고 가정하고, 코틀린에서 콜렉션을 어떻게 사용하는지 예제와 함께 알아보겠습니다.
List
List는 데이터가 저장하거나 삭제될 때 순서를 지키는 Collection입니다. List는 Mutable(변할 수 없는)과 Immutable(불변의)을 모두 지원합니다.
List : Immutable(수정할 수 없는 객체, 불변의)
listOf<타입>(아이템, )
로 Immutable List를 생성 및 초기화를 할 수 있습니다. 코틀린은 아이템의 타입을 추론하기 때문에 타입을 생략해도 됩니다.
Immutable이기 때문에 get만 가능합니다. List의 getter는 자바처럼 get(index)
도 지원하고 배열처럼 [index]
도 지원합니다.
코틀린은 간결하고 직관적인 배열같은 표현 방식을 선호합니다.
val fruits= listOf<String>("apple", "banana", "kiwi", "peach")
// val fruits= listOf("apple", "banana", "kiwi", "peach") -> 타입 생략 가능
println("fruits.size: ${fruits.size}")
println("fruits.get(2): ${fruits.get(2)}")
println("fruits[3]: ${fruits[3]}")
println("fruits.indexOf(\"peach\"): ${fruits.indexOf("peach")}")
위의 코드를 실행한 결과입니다.
fruits.size: 4
fruits.get(2): kiwi
fruits[3]: peach
fruits.indexOf("peach"): 3
List : Mutable(수정가능한 객체, 변할 수 있는)
수정가능한 List는 mutableListOf
로 선언합니다. listOf
와 대부분 비슷하지만, 추가 및 삭제가 가능합니다.
자바의 Collection에 익숙하시다면 remove, add, addAll, removeAt 등은 이미 알고 계실 것입니다.
val fruits= mutableListOf<String>("apple", "banana", "kiwi", "peach")
fruits.remove("apple")
fruits.add("grape")
println("fruits: $fruits")
fruits.addAll(listOf("melon", "cherry"))
println("fruits: $fruits")
fruits.removeAt(3)
println("fruits: $fruits")
위의 코드를 실행한 결과입니다.
fruits: [banana, kiwi, peach, grape]
fruits: [banana, kiwi, peach, grape, melon, cherry]
fruits: [banana, kiwi, peach, melon, cherry]
그 외에도 replace, replaceAll, contains, forEach 등의 메소드도 지원합니다.
Set
Set은 동일한 아이템이 없는 Collection입니다. Set의 아이템들의 순서는 특별히 정해져 있지 않습니다. Set은 null 객체를 갖고 있을 수 있습니다. 동일한 객체는 추가될 수 없기 때문에 null도 1개만 갖고 있을 수 있습니다. List와 같이 Set도 Immutable과 Mutable을 별개로 지원합니다.
Set : Immutable
setOf<타입>(아이템들)
로 객체를 생성할 수 있습니다. 다음과 같이 객체 아이템들을 확인할 수 있습니다.
val numbers = setOf<Int>(33, 22, 11, 1, 22, 3)
println(numbers)
println("numbers.size: ${numbers.size}")
println("numbers.contains(1): ${numbers.contains(1)}")
println("numbers.isEmpty(): ${numbers.isEmpty()}")
실행 결과입니다.
[33, 22, 11, 1, 3]
numbers.size: 5
numbers.contains(1): true
numbers.isEmpty(): false
forEach 또는 Iterator 등으로 모든 객체를 탐색할 수도 있습니다.
Set : Mutable
Mutable은 mutableSetOf<타입>(아이템들)
로 생성할 수 있습니다. Mutable이기 때문에 추가, 삭제가 가능합니다.
List와 비슷한 메소드들을 지원합니다.
val numbers = mutableSetOf<Int>(33, 22, 11, 1, 22, 3)
println(numbers)
numbers.add(100)
numbers.remove(33)
println(numbers)
numbers.removeIf({ it < 10 }) // 10 이하의 숫자를 삭제
println(numbers)
실행 결과 입니다.
[33, 22, 11, 1, 3]
[22, 11, 1, 3, 100]
[22, 11, 100]
Map
Map은 key와 value를 짝지어 저장하는 Collection입니다. Map의 key는 유일하기 때문에 동일한 이름의 key는 허용되지 않습니다.에 Map 또한 Immutable과 Mutable을 별개로 지원합니다.
Map : Immutable
Map은 mapOf<key type, value type>(아이템)
로 생성할 수 있습니다. 아이템은 Pair객체로 표현하며, Pair에 key와 value를 넣을 수 있습니다.
Pair(A, B)
는 A to B
로 간단히 표현이 가능합니다. 이런 문법이 가능한 것은 to가 Infix이기 때문입니다.
val numbersMap = mapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap: $numbersMap")
val numbersMap2 = mapOf(Pair("1", "one"), Pair("2", "two"), Pair("3", "three"))
println("numbersMap2: $numbersMap2")
// 실행해보면 모두 동일한 값을 갖고 있습니다.
// numbersMap: {1=one, 2=two, 3=three}
// numbersMap2: {1=one, 2=two, 3=three}
Map의 데이터를 읽는 것도 다른 Collection과 유사합니다. getter는 get(index)
와 [index]
를 모두 지원합니다. 코틀린은 배열 방식을 선호합니다.
keys
와 values
는 key와 value만으로 구성된 Set을 리턴해줍니다.
val numbersMap = mapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap.get(\"1\"): ${numbersMap.get("1")}")
println("numbersMap[\"1\"]: ${numbersMap["1"]}")
println("numbersMap[\"1\"]: ${numbersMap.values}")
println("numbersMap keys:${numbersMap.keys}")
println("numbersMap values:${numbersMap.values}")
for (value in numbersMap.values) {
println(value)
}
실행 결과입니다.
numbersMap.get("1"): one
numbersMap["1"]: one
numbersMap["1"]: [one, two, three]
numbersMap keys:[1, 2, 3]
numbersMap values:[one, two, three]
one
two
three
Map : Mutable
Mutable은 mutableMapOf<key type, value type>(아이템)
로 생성합니다. 객체 추가는 put
메소드이며, Pair를 사용하지 말고 인자로 key와 value를 넣어주면 됩니다.
put
도 배열 방식을 지원합니다. 그 외에 자바의 Map과 유사합니다.
val numbersMap = mutableMapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap: $numbersMap")
numbersMap.put("4", "four")
numbersMap["5"] = "five"
println("numbersMap: $numbersMap")
numbersMap.remove("1")
println("numbersMap: $numbersMap")
numbersMap.clear()
println("numbersMap: $numbersMap")
실행 결과 입니다.
numbersMap: {1=one, 2=two, 3=three}
numbersMap: {1=one, 2=two, 3=three, 4=four, 5=five}
numbersMap: {2=two, 3=three, 4=four, 5=five}
numbersMap: {}
Collection
List와 Set은 Collection을 상속합니다. 이 클래스들은 Collection에 대입할 수 있기 때문에 아래와 같이 사용할 수 있습니다.
fun printAll(strings: Collection<String>) {
for(s in strings) print("$s ")
println()
}
val stringList = listOf("one", "two", "one")
printAll(stringList)
val stringSet = setOf("one", "two", "three")
printAll(stringSet)
실행 결과 입니다.
one two one
one two three
정리
코틀린의 Collection인 Map, Set, List에 대해서 알아보았습니다. 자바와 다른 것은 Mutable과 Immutable을 구분하여 지원한다는 점입니다. 그 외의 지원하는 메소드는 자바와 거의 유사합니다.
참고
Recommended Posts:
- Kotlin - Collections와 Sequences의 차이점
- Kotlin - Reified를 사용하는 이유?
- Kotlin - Sealed class 구현 방법 및 예제
- Kotlin - inline functions 이해하기
- Kotlin - Destructuring Declaration
- KotlinTest로 Unit Test 작성하는 방법
- Kotlin - Data class 이해 및 구현 방법
- Kotlin에서 자주 사용하는 annotation 정리
- Kotlin - Generics 클래스, 함수를 정의하는 방법
- Kotlin - lateinit과 Delegates.notNull의 차이점
- Kotlin - Delegates로 프로퍼티를 Observerable로 만들기
- Kotlin - Null을 안전하게 처리하는 방법 (Null safety, 널 안정성)
- Kotlin - lateinit과 lazy로 초기화를 지연하는 방법