콜렉션의 종류
자바에서도 이미 충분한 collection을 제공하고 있기에, 코틀린이 어떤 역할을 하는지 궁금하다.
코틀린이 제공해주는 collection의 진화는 총 두가지다.
kotlin.collections 패키지에 Java 콜렉션에 유용한 함수들이 많음
자바와 비교하기
Java의 명렬형 스타일 for-Each가 아닌 함수형 스타일의 forEach문을 사용한다면 인덱스 사용 불가
⬇️
Kotlin의 withIndex() 메소드 -> 인덱스와 값 모두를 편하게 얻게 해줌
for ((index, value) in names.withIndex()){ """ }
immutable collection : 동시성을 사용하는 함수형 프로그래밍 또는 비동기 처리를 하는 애플리케이션을 사용할 때 훨씬 안정적이다.
Java : 대부분의 collection은 mutable이고, 최근 이뮤터블 콜렉션이 생겼지만, 변경 시도를 하면 실행시간에 UnsupportedOperationException이 나옴
⬇️
Kotlin : 연산이 불가능함을 실행 시간이 되어서야 알리지 않는다. 무슨말이지..?
list, set, map의 두 가지 뷰 : immutable (읽기전용 뷰), mutable (읽기-쓰기 뷰)
-> 사용 시 오버헤드가 없고, 컴파일 시간이나 실행 시간에 변환이 발생하지 X
읽기 전용 뷰가 thread safety를 제공해준다고 보장할 수는 없음.
읽기전용 참조는 mutable collectiond이며 콜렉션을 변경할 수는 없지만, 다른 스레드가 참조하고 있는 콜렉션을 변경하지 않았다는 걸 보장해 주지 않는다...?
여러 개의 뷰가 같은 인스턴스를 참조하고 있는 중이고, 그 중 일부는 읽기 전용, 일브는 읽기-쓰기 용으로 사용된다면 사용 시 두 개의 쓰레드에서 읽기-쓰기 뷰를 이용해서 동시에 한 콜렉션을 변경하지 않도록 주의!!
튜플- 2, 3개의 튜플만 허용
println(Pair("Tom", "Jerry"))
println(mapOf("Tom" to "Cat", "Jerry" to "Mouse"))
페어의 장점 예제 : 공항의 온도를 공항 코드별로 수집해주는 코드이다.
val airportcodes = listOf("LAX", "SFO", "PDX", "SEA")
val temperarues = airportcodes.map { code -> code to getTemperatureAtAirport(code) }
for (temp in temperatures) {
println("Airport: ${temp.first} : Temperature: ${temp.second}")
}
코틀린의 페어는 간결한 코드를 만들 수 있을 뿐만 아니라, 컴파일 시간에서 타입 안정성 또한 제공한다.
페어와 트리플은 모두 immutable, mutable collection의 값들을 취급하는 콜렉션을 위해선 배열이 좋은 선택이다.
배열은 낮은 수준의 최적화가 필요할 때만 사용,
그 외엔 List같은 자료구조를 사용하라!
이뮤터블과 뮤터블을 선택할 수 있는 경우에는 이뮤터블을 선호해야한다! 하지만 꼭 필요해서 뮤터블 리스트를 만들어야 한다면 mutableList()를 사용해라
listof() function -> immutable, 리스트의 요소들에 접근하기 위해 전통적인 get() 메소드 사용가능! 하지만 get() 대신 []를 사용하는 편이 좋다.
이런 뷰를 제공해주기 때문에, 코틀린은 뷰의 변경 불가능한 부분을 이용해서 코드를 더 안전하게 만ㄷ르고 실행 시간에 오버헤드나 변경이 없도록 만든다. 😬
다른 요소를 추가하고 싶다면 add() 대신 + 연산자를 사용할 수 있다. 기존 list를 변경시키는 것이 아닌, 카피하면서 새로운 list를 만들고 새로운 요소를 추가하는 것이다!
셋은 정렬되지 않은 요소의 모음이다. 이뮤터블/읽기 전용 버전과, 뮤터블/읽기-쓰기 버전 모두 있다. (setof(), Mutablesetof())
+ hashSetOf(), linkedSetOf(), sortedSetOf()
key-value 페어를 보관하는 collection 🫥
JDK의 맵에서 사용 가능한 모든 method는 mutable interface에서 사용이 가능하다. immutable에서는 읽기 전용만 가능하다.
immutable, 읽기 전용의 Map 인터페이스를 만들고 요소에 접근하자!
ex>
val sites = mapOf("pragprog" to "https://www.pragprog.com", "agiledeveloper" to "https://agiledeveloper.com")
# containsKey(), containsValue() 메소드를 통해 각 존재여부 파악 가능!
get() 메소드는 key가 맵에 존재하지 않을 때 nullable 타입 리턴, 오류 🤒
-> nullable 참조를 피하기 위해 키가 없으면 기본값을 리턴하도록 함 !!
(getOrDefault(key값, default값) 메소드)
mapOf() 함수는 읽기 전용 참조만 전달해주므로 Map 변경 불가능, 하지만 key-value pair를 추가해서 새로운 맵 생성 가능~!!
val sitesWithExample = sites + ("example" to "https://www.example.com")
for문을 사용한 구조분해 :
for ((key, value) in sites) {
println( "$key --- $value")
}
정리, 코틀린은 Java의 콜렉션을 확장시키는 동시에, 읽기 전용 뷰를 통해 컴파일 시간의 안정성도 향상시킴. 함수형 코드를 쓰거나, 동시성 코드를 작성하거나, 비동기 프로그램을 만들 때는 읽기 전용 뷰를 사용해야 한다.
작은 크기의 콜렉션 - pair & tripple 사용
크고 고정된 크기의 콜렉션 - Array
이렇게 5챕터 정리도 끝이 났다 ~~!! 🫶🫶
이번 챕터에서는 반복자를 이용하는 방법을 배웠다.
다음 챕터에서는 코틀린이 컴파일 시 타입 안정성을 제공하는 완전히 새로운 방법에 대해 알아본다고 한다. 타입 안정성은 프로그래밍에 있어서 개인적으로 상당히 많이 중요하다고 생각하고 있기 때문에 매우 기대중..!