코틀린 널 대응

Kotlin에서 NullPointerException에 대처하는 방법을 살펴봅니다.

2022-05-12

kotlinnull valuesafe call

Kotlin에서 null은 하나의 값입니다. 그러나 아무 변수에나 null을 할당할 수는 없습니다.

fun main() {
    var num:Int = 3
    num = null
}

error: null can not be a value of a non-null type Int

null이 non-null 타입 Int의 값이 될 수 없다는 에러가 뜹니다.

널러블 타입 nullable type

타입 이름 뒤에 '?' 기호를 추가하면 null을 할당할 수 있게 됩니다.

    var num:Int? = 3
    num = null

세이프 콜 safe call

만약 myCar라는 오브젝트가 drive()라는 메소드를 부를 수 있다고 할 때, NullPointerException을 피하기 위해 if문으로 확인해 볼 수 있습니다.

if (myCar != null) {
    myCar.drive()
}

그렇지만 어떤 경우에는 이 코드가 컴파일되지 않을 수도 있습니다. if 확인과 drive() 메소드 콜 사이에도 다른 코드가 껴들어 오브젝트를 업데이트할 수 있는 경우도 있기 때문입니다. 그래서 코틀린에서는 세이프 콜(safe call)이라는 방법을 사용합니다.

myCar?.drive()

myCar가 null이 아니라면 drive() 메소드를 수행하지만, myCar가 null이라면 아무것도 하지 않습니다.

myCar에 speed라는 속성이 있을 때, myCar?.speed도 마찬가지입니다. myCar가 null이 아니라면 speed 값을 반환하지만, myCar가 null이라면 null을 반환합니다.

let과 it

오브젝트 속성을 다른 함수 안에 인자로 넣는 경우에는 다음과 같이 세이프 콜을 수행할 수 있습니다. let을 사용합니다.

myCar?.let {
    println(it.speed)
}

오브젝트와 ? 뒤에 .let을 붙이고 {} 스코프를 만든 후, 그 안에서 오브젝트를 it으로 받아 활용합니다. 여기서 it은 myCar를 가리키며, null이 아닙니다. 만약 myCar가 null이라면 let의 {} 내부 코드가 전부 수행되지 않을 것입니다.

엘비스 오퍼레이터

엘비스 오퍼레이터(?:)는 한 줄짜리 if문과 비슷합니다. ?: 이 기호를 오른쪽에서 보면 엘비스 프레슬리의 헤어스타일과 닮았다고 해서 엘비스 오퍼레이터입니다.

myCar?.speed ?: 0

위 표현은 myCar가 null이 아니라면 speed 속성을 반환하지만, 만약 null이라면 speed 속성 대신 0을 반환합니다.

not-null assertion operator

의도적으로 NullPointerException을 던지게 만들 수도 있습니다.

myCar!!.drive()

myCar가 null이 아니라면 코드는 정상적으로 수행되지만, null이라면 NullPointerException을 던집니다. 코드를 테스트할 때 유용합니다.