자바로 개발하다 보면 NPE(Null Pointer Exception)를 종종 보게 된다. 자바에서는 객체가 null인지 아닌지 if문을 통해 직접 확인하지 않으면 알 수가 없기 때문이다.
Object obj = foo(); //만약 foo가 null을 반환하게된다면
obj.toString() //NPE가 발생하게된다.
if(obj != null) { //if문을 통해 null값을 체크해주어야 한다.
obj.toString();
}
하지만 어떤 값이 null이 될 지 몰라 위와 같이 매번 체크하게되면 코드가 상당히 지저분해지게 된다. 그래서 Java8 부터는 Optional을 이용해 null이 될 수 있는 객체를 감싸서 명시적으로 구분할 수 있게 되었다. 하지만 이 Optional도 반환 타입에서 쓰도록 설계된것이라 사용이 제한적일 수 있다.
그렇다면 코틀린에서는 null을 어떻게 다루고 있을까?
코틀린에서는 기본적으로 타입이 non-nullable하다. 만약 nullable하다면 ?를 붙여 null이 될 수 있음을 명시적으로 나타내야 한다.
val a: String = null // 컴파일 오류 발생
val b: String? = null // 정상 작동
그렇다면 nullable한 값을 다룰때는 어떻게 해야 할까. 자바처럼 if로 처리할 수도 있지만 코틀린에서는 이를 위한 연산자가 존재한다.
var a:String? = null
//if
if(a != null) {
a.trim()
}
println(a)
//safe call
a?.trim() //trim()을 실행하지 않는다.
println(a)
?.를 사용하면 null인지 검사하여 null이면 실행하지 않고 건너뛰고 null이 아니면 실행한다.
var a:String? = null
//if
val b:String = if (a != null) a.toUpperCase() else "empty"
//?:
val c:String = a?.toUpperCase() ?: "empty"
엘비스 연산자(?:) 왼쪽에 있는 값이 null이면 오른쪽 값을 null이 아니면 왼쪽을 반환한다.
오른쪽에 return이나 throw도 사용할 수 있다.
val a:String = getSomeString()!!.length
!!연산자는 값이 null이 아님을 단언하는 연산자이다. 로직상 절대 null이 들어가지 않는다는 확신이 있을때만 사용해야한다. 그렇지 않으면 NPE가 발생할 수 있기때문에 주의해야한다. (권장 x)
참고:https://kotlinlang.org/docs/null-safety.html#collections-of-a-nullable-type