Kotlin

[Kotlin] Map에서 정수 value 값 Type mismatch (`Int`와 `Int?`의 차이, `!!`의 의미)

Alsong 2023. 11. 13. 18:46

맵 사용 중 Type mismatch 오류

코틀린에서 자주 사용하게 되는 자료구조인 Map을 사용하다가, 다음과 같은 문제가 발생할 때가 있습니다.

val myMap: Map<String, Int> = mapOf("a" to 1, "b" to 2)

var myInt: Int = 0
myInt += myMap["a"]

Map<String, Int> 타입의 myMap 안의 value를 myInt에 더해주고 싶은데, 이렇게 작성하면 다음과 같이 Type mismatch오류가 발생합니다.

 

분명 myMap의 value는 정수 타입인데, 타입이 맞지 않는다고 합니다. 왜일까요?

 

그것은 바로 myMap["a"]의 타입이 Int가 아니라 Int?이기 때문입니다.  

 

 

Int와 Int?의 차이는?

Int?nullable Int를 의미합니다. nullable이란 'null을 가질 수 있는'이라는 뜻이죠. 즉 '정수이긴 한데 null을 가질 수 있는 정수 타입' 이라는 것입니다. 그래서 타입 미스매치가 발생하는 것입니다.. myInt는 Int 타입인데, Int?를 더하려고 하니까요.

 

IntInt?는 코틀린에서 null 안전성을 강화하기 위해 도입된 기능 중 하나입니다. 이를 통해 코드에서 명시적으로 null 여부를 다룰 수 있으며, 런타임에서의 NullPointerException을 방지할 수 있습니다.

 

 

타입을 Map<String, Int>로 정했는데 왜 Int?가 된 거죠?

그럼 "나는 myMap의 타입을 Map<String, Int>로 정했는데, 왜 지 멋대로 Map<String, Int?>로 바꾸느냐!" 라는 의문이 들 수 있습니다. 하지만 사실 Map<String, Int?>로 바뀐 것이 아니라, myMap["a"]의 타입이 Int?인 것 뿐입니다. 맵에서 특정 키에 해당하는 값이 없을 경우 null을 반환하게 되므로 해당 키에 대한 값이 null일 수 있기 때문입니다.

따라서 myMap의 타입은 Map<String, Int>이지만, myMap["a"]의 타입은 Int?가 됩니다. myMap에서 "a" 키에 해당하는 값이 항상 존재한다는 보장이 없으므로 해당 값은 nullable로 취급되는 것입니다.

 

 

그럼 타입을 어떻게 맞춰주나요?

오류가 나는 원인을 알았으니, 이를 어떻게 해결하는지도 알아보겠습니다. myMap["a"]가 담길 임시 변수를 하나 선언하고, 그 변수가 null인지를 판단해서 null이 아닐 때 더해주면 됩니다. (참고로 임시 변수를 만들지 않으면 여전히 Type mismatch 오류가 발생합니다!! 궁금하신 분들은 한 번 해보시길..)

val myMap: Map<String, Int> = mapOf("a" to 1, "b" to 2)

var myInt: Int = 0
val temp = myMap["a"]
if (temp != null){
    myInt += temp
}

 

그런데 이렇게 작성했더니 if문도 써야 하고 임시 변수도 하나 만들어야 해서 너무 지저분해지고 가독성도 현저히 떨어지는군요.. 그래서 아래와 같이 하는 것을 추천드립니다.

 

val myMap: Map<String, Int> = mapOf("a" to 1, "b" to 2)

var myInt: Int = 0
myInt += myMap["a"]!!

 

이 코드에서 !!는 null을 허용하지 않는 단언 연산자입니다. 즉, 이렇게 함으로써 컴파일러에게 "여기서는 값이 항상 null이 아니라고 가정해도 좋다" 라고 전달하는 것이죠! 만약 해당 키에 대응하는 값이 항상 존재한다는 것을 확신한다면 이런 식으로 사용할 수 있습니다. 하지만 만약 값이 null이라면 런타임에 NullPointerException이 발생할 수 있습니다. 따라서 사용 시 주의가 필요합니다.

 

만약 null이 아님을 확신할 수 없다면 다음과 같이 쓸 수도 있습니다.

val myMap: Map<String, Int> = mapOf("a" to 1, "b" to 2)

var myInt: Int = 0
myInt += myMap["a"]?: 0

 

myMap["a"]?: 0은 만약 myMap["a"]가 null이라면 0으로 처리하겠다는 뜻입니다. 이렇게 하면 코드의 안정성이 더 올라갑니다.