Map 은 key 와 value 로 구성된 자료 구조이다. 중복되는 value 는 가질 수 있지만, 중복된 key 를 가질 수는 없다.
class Recipe (val title: String) {}
fun main() {
val myMap: Map<String, Recipe> = mapOf("R1" to Recipe("Soup"), "R2" to Recipe("Steak"))
println(myMap.containsKey("R1")) // true
println(myMap.containsValue(Recipe("Soup"))) // false
println(myMap.get("R1")?.title) // Soup
println(myMap.get("R3")?.title) // null
println(myMap.getValue("R1").title) // soup
println(myMap.getValue("R3").title) // NoSuchElementException
}
map 을 초기화 하기 위해서는 key, value pair 를 넣어줘야한다. 이때 key 값은 to 를 이용해서 어떤 value 의 key 가 되는지 명시되어야 한다.
containsKey() 와 containsValue() 를 이용해서 해당 값을 가지고 있는지 확인 할 수 있다. myMap.containsValue(Recipe("Soup"))
의 결과가 false 인 것은 통해 containsValue() 역시 내부적으로 ===, equals() 를 이용하고 있을 것이라고 짐작할 수 있다.
class Recipe (val title: String) {
override fun hashCode(): Int {
return title.hashCode()
}
override fun equals(other: Any?): Boolean {
return this.hashCode() == other.hashCode()
}
}
Recipe class 에 hashCode() 와 equals() 를 위와 같이 override 하고 다시 myMap.containsValue(Recipe("Soup"))
를 돌려보면 그 결과가 true 로 나오게 된다. title 이 똑같으면 참조값이 어떻든 equivalent 하다고 인식하게 만든 것이다.
get() 함수는 주어진 key 값을 찾을 수 없다면 Null 을 반환하는 반면, getValue() 함수는 예외(Exception)를 발생시킨다.
List, Set 과는 다르게 Map 이 저장하는 값은 Key, Value Pair 이다. 똑같은 방법으로 loop 를 돌리면 돌아가긴 하지만, 아마도 우리가 원하는 값을 보여주진 않을 것이다. {key}={valueInfo} 이런 정보가 출력되기 때문이다.
for (item in myMap) {
println(item)
}
//R1=Recipe@276a17
//R2=Recipe@4c7e12e
for ((key, value) in myMap) {
println("$key=$value")
}
대신 두번째 for문 처럼 구성하면 key 와 value 각각에 접근이 가능하다.
mutableMap 을 만드는 방법은 예상 되듯이 mutableMapOf() 함수를 사용하는 것이다.
put
을 이용해서 내용물을 추가할 수 있고 또한 assignment
를 이용해서 내용물을 추가할 수 있다. IntelliJ 는 assignment 방법을 추천하는 것 같다. 이는 Java 로 치면 set 을 이용해서 map 의 내용물을 바꾸는 거라는데, 무슨 차이가 있는 걸까? kotlin 문서 에서는 put 도 쓰고있고 굳이 assignment 방식으로 전환해야 하는 이유를 말하고 있지 않다.
remove()
를 이용해서 내용물을 제거할 수 있다.
원래는 put 을 이용해서 map 에 내용물을 추가할 수 있지만, 이를 assignment 방식으로 바꾸는 것이 추천되고 있다.
fun main() {
val myMap: Map<String, Recipe> = mapOf("R1" to Recipe("Soup"), "R2" to Recipe("Steak"))
val mutableMap = mutableMapOf("R3" to Recipe("Kimchi"), "R4" to Recipe("SoonDae"))
mutableMap.put("R5", Recipe("Ramen"))
mutableMap["R6"] = Recipe("Galbijjim") // recommended...but Why?
mutableMap.putAll(myMap)
mutableMap.remove("R4")
mutableMap.remove("R3", Recipe("Kimchi"))
mutableMap.clear()
}
역시 Map 도 copy 를 만들 수 있다. 특이하게도 List 로도 바꿀 수도 있는데, 그 결과물은 이런 식이다. 각 map 의 key, value pair 를 하나의 원소로 가지고 있는 리스트가 만들어진다.
(R5, Recipe@4b14527)
(R6, Recipe@79a2245d)
(R1, Recipe@276a17)
(R2, Recipe@4c7e12e)
또한 entries
라는 프로퍼티를 이용하면 map 의 내용물을 set 으로 반환 받을 수 있는데, mutableMap 에서 쓰면 mutableSet, 반대는 그냥 set이 반환된다. 또한 keys 프로퍼티를 이용해서 key 의 sey을, values 를 이용해서 value 의 Generic Collection을 얻을 수 있다. 반환받은 자료 구조가 이 mutable 인지 아닌지는 위와 같이 map 의 성격에 따라 결정된다.
keys , values 프로퍼티는 copy 가 아니라 실제 map 을 구성하는 요소이다. 만약 mutable map 에서 가져온 프로퍼티라면, 이를 변경함으로써 map을 업데이트 할 수 있다.
immutable, mutable 을 나눔으로써 업데이트 되면 안되는 collection 이 다른 코드에서 업데이트 되는 실수를 방지할 수 있다고 한다.
val x = mutableSet(1, 2,)
val y: Set<Int> = x
이렇게 하고 y만 보여준다면, 동일한 내용물을 업데이트 할 수 없는 버전으로 보여줄 수 있다.