Collections
Kotlin은 변경 가능하고 불가능한 콜렉션 (List, Set, Map 등)을 구별한다.
Kotlin의 List<out T>
타입은 크기
, get
등과 같은 읽기 전용 연산을 제공하는 인터페이스이다. 자바와 마찬가지로 Iterable<T>
의 하위 타입인 Collection<T>
을 상속받는다. 리스트를 변경할 수 있는 메소드는 MutableList<T>
인터페이스에 정의되어 있다. 이 패턴은 Set<out T>/MutableSet<T>
과 Map<K, out V>/MutableMap<K, V>
에도 적용된다.
리스트와 집합의 기본 사용법은 아래와 같다.
val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = numbers
println(numbers) // "[1, 2, 3]" 출력
numbers.add(4)
println(readOnlyView) // "[1, 2, 3, 4]" 출력
readOnlyView.clear() // -> 컴파일되지 않음
val strings = hashSetOf("a", "b", "c", "c")
assert(strings.size == 3)
Kotlin은 리스트나 집합을 생성하기위한 전문 구문을 가지고 있지 않다. listOf()
, mutableListOf()
, setOf()
, mutableSetOf()
와 같은 표준 라이브러리의 메소드를 사용한다. 성능이 중요하지않은 코드에서 맵을 생성할 때 mapOf(a to b, c to d)
이디엄을 사용할 수 있다.
readOnlyView
변수는 동일한 리스트를 가리키며, 기본 리스트가 변경되면 같이 변경된다. 리스트에 대한 유일한 참조가 읽기 전용 변수라면 완전한 불변 콜렉션을 사용할 것을 고려하자. 불변 콜렉션을 만드는 것은 다음과 같다.
val items = listOf(1, 2, 3)
listOf
메소드는 배열 리스트를 사용해 구현되고 있지만, 불변 리스트를 생성하므로 메모리에 더 효율적인 불변 콜렉션 타입을 리턴하도록 구현한다.
읽기 전용 타입은 공변(covariant)이다.
즉, Rectangle이 Shape에 상속받은 경우 List<Rectangle>를 List<Shape>에 할당할 수 있다는 뜻이다. 변경가능 콜렉션은 런타임에 실패를 발생할 수 있기때문에 이를 허용하지 않는다.
class Controller {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items.toList()
}
toList
확장 메소드는 리스트 항목을 복제하므로 반환된 리스트변경되지 않는다.
다양한 유용한 확장 함수가 있다.
val items = listOf(1, 2, 3, 4)
items.first() == 1
items.last() == 4
items.filter { it % 2 == 0 } // [2, 4] 리턴
val rwList = mutableListOf(1, 2, 3)
rwList.requireNoNulls() // [1, 2, 3] 리턴
if (rwList.none { it > 6 }) println("No items above 6") // "No items above 6" 출력
val item = rwList.firstOrNull()
또한 sort, zip, fold, reduce 와 같은 유틸리티도 존재한다.
맵도 동일한 패턴을 따른다. 다음과 같이 생성하고 접근할 수 있다.
val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
println(readWriteMap["foo"]) // "1" 출력
val snapshot: Map<String, Int> = HashMap(readWriteMap)