Null Safety
Nullable types (?) and non-null types ()
코틀린의 타입 시스템은 위험한 널 참조를 제거하는 것을 지향합니다.
자바의 경우 NPE(NullPointerException)를 알기 위해서는 프로그램을 실행하여야만 합니다. 또한 NPE를 예방하기위해 예외처리를 try-catch와 같은 구문으로 일일이 해주어야합니다.
→ 코틀린에서는 물음표 기호로 nullable인지 nonnull인지를 미리 정해줄 수 있습니다.
타입에 물음표(?) 기호가 있는 경우 : nullable
타입에 물음표(?) 기호가 없는 경우 : nonnull
var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error
var b: String? = "abc" // can be set to null
b = null // ok
이렇게 함으로써 null이 가능한지 아닌지를 미리 정해주어 물음표(?)가 없는 경우 null값이 불가능하므로 null값에는 적용이 불가능한 메소드를 사용하더라도 NPE로부터 안전함을 보장할 수 있게 됩니다.
만약 nullable한 property에 대해 메소드를 사용하려는 경우 error를 냅니다.
val l = a.length
val l = b.length // error: variable 'b' can be null
nullable한 property에 대해서도 접근이 필요한 경우에는 몇가지 방법을 통해 실행을 시킬 수 있습니다.
첫번째 방법으로 condition구문을 통해 null check를 함으로써 실행이 가능합니다. 다만 nullable property가 mutable한 경우 check후에 null이 될 수도 있으므로 반드시 immutable해야 합니다.
val l = if (b != null) b.length else -1
두번째방법으로 safe call operator인 ?.을 사용하는 것입니다.
?.을 사용하여 null일 경우 null을 반환하고 nonnull인 경우 정상적으로 실행시킵니다.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length) // Unnecessary safe call
nonnull일 경우 특정 statment를 실행시키고 싶을 때는 ?.let{}을 사용할 수 있습니다.
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints Kotlin and ignores null
}
두 가지 방법 모두 null check를 미리 해줌으로써 null safety를 보장하게됩니다.
Elvis Operator (?:)
nullable한 property에 대해서 접근이 필요할 경우 조건문이나 safe call operator를 이용하여 null을 체크하여 실행을 시킬 수 있었습니다. 다만 safe call operator를 이용할 경우 null일 경우에는 null을 반환하였지만, Elvis Operator를 이용할 경우 조건문을 이용하는 것과 같이 null일 경우에는 다른 nonnull값을 반환할 수 있도록 할 수 있습니다.
val l = b?.length ?: -1
not-null assertion operator (!!)
for NPE-lovers.
val l = b!!.length
b가 Null일 경우에도 실행되어 NPE 반환.
Safe casts
일반적으로 casts 시에 object가 target type이 아닌 경우 ClassCastException를 발생 시킵니다. 이를 방지하기 위해 아래와 같이 적용을 하면 ClassCastException을 일으키는 대신 null을 반환합니다.
val aInt: Int? = a as? Int
Collections of a nullable type
collection에서 null값을 배제하고 싶은 경우, .filterNotNull()을 사용하면 됩니다.
val nullableList: List<Int?> = listOf(1, 2,null, 4)
val intList: List<Int> = nullableList.filterNotNull()
참고 문헌 : https://kotlinlang.org/docs/null-safety.html#safe-casts