Kotlin에서 null + null의 동작 원리
Kotlin에서 null + null의 동작 원리
Kotlin은 null 안전성(null safety) 시스템을 통해 null 값을 안전하게 처리하지만, null과 관련된 일부 동작은 여전히 개발자를 놀라게 할 수 있습니다. 면접에서 자주 등장하는 주제 중 하나가 바로 null + null을 평가하면 어떤 결과가 나오는지에 대한 질문입니다. 흥미롭게도, 이 표현식은 컴파일 에러나 NullPointerException을 발생시키지 않고 문자열 "nullnull"을 반환합니다. 이러한 동작이 발생하는 이유를 이해하려면, Kotlin이 + 연산자를 어떻게 해석하는지, 그리고 null이 String.plus() 확장 함수와 어떻게 상호작용하는지를 살펴봐야 합니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
null + null이 컴파일 에러가 아닌 문자열"nullnull"을 생성하는 이유를 설명할 수 있습니다.- Kotlin이
+연산자를String.plus()를 통해 해석하는 방식을 이해할 수 있습니다. null.toString()이null을 문자열"null"로 변환하는 과정을 파악할 수 있습니다.null과 관련된 다른 연산자 동작 중 예상치 못한 결과를 만들어낼 수 있는 케이스를 알 수 있습니다.
Plus 연산자가 null에서 해석되는 방식
Kotlin에서 null + null을 만나면, 컴파일러는 적용 가능한 plus 함수를 탐색합니다. Kotlin 표준 라이브러리에는 문자열 연결(string concatenation)을 위해 Any?에 정의된 확장 함수가 존재합니다.
public operator fun Any?.plus(other: Any?): String {
return toString() + other.toString()
}
Any?는 null을 포함하므로, 좌측 피연산자가 null일 때도 이 확장 함수가 매칭됩니다. 컴파일러는 이 오버로드를 선택하여 호출 코드를 생성하게 됩니다. 결과적으로 null + null이라는 표현식은 호출 시점에서 null.plus(null)로 변환됩니다.
이 부분은 면접에서 "Kotlin에서
null에 대해+연산을 수행하면 어떤 일이 벌어지나요?"라는 질문으로 나올 수 있으므로,Any?확장 함수의 존재를 정확히 알고 계시는 것이 중요합니다.
null.toString()의 동작 방식
Any?에 정의된 toString() 함수는 null을 명시적으로 처리합니다. 수신 객체가 null인 경우, 문자열 리터럴 "null"을 반환합니다.
public fun Any?.toString(): String {
return this?.toString() ?: "null"
}
따라서 null.plus(null)이 실행될 때, 수신 객체에 대한 첫 번째 toString() 호출은 "null"을 반환하고, 인자에 대한 두 번째 toString() 호출 역시 "null"을 반환합니다. 이 두 문자열이 연결되어 최종적으로 "nullnull"이 생성됩니다.
val result = null + null
println(result) // 출력: nullnull
println(result.length) // 출력: 8
이 표현식의 반환 타입은 String?이 아닌 String입니다. 컴파일러가 plus 확장 함수의 반환 타입으로부터 이를 추론하기 때문입니다. 따라서 결과값에 대해 .length를 바로 호출해도 안전합니다.
null 피연산자를 포함한 문자열 연결
이 동작은 null과 + 연산자가 문자열 컨텍스트에서 결합되는 모든 경우에 동일하게 적용됩니다. 한쪽 피연산자가 String이고 다른 쪽이 null인 경우에도 같은 toString() 변환이 수행됩니다.