본문 바로가기

카테고리 없음

kotlin null safety

728x90

코틀린을 시작하면서 신기한 연산자를 정리 했습니다.

기본적으로 kotlin은 null을 허용하지 않습니다.

다만 명시적으로 null을 허용할수 있는데요.

// null 할당시 오류
var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error

// null 명시적 허용 처리
var b: String? = "abc" // can be set to null
b = null // ok
print(b)

// null 인 b의 length에 접근시 오류 발생
val l = b.length // error: variable 'b' can be null

명시적으로 null을 허용하게 하였다면, 해당 변수의 null 체크는 필수가 되는데요. 코틀린은 이를 어떻게 처리 할까요?

일반적인 null 체크 문법

val b: String? = "Kotlin"
// null 확인 방법 1
if (b != null && b.length > 0) {
    print("String of length ${b.length}")
} else {
    print("Empty string")
}

// null 확인 2
val l = if (b != null) b.length else -1

안전한 호출

값을 리턴하는게 아니라면, b?.length 사용하면 오류 없이 호출이 가능합니다. 단, null 일 경우 null 을 리턴합니다.

val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length) // Unnecessary safe call

// 결과
null
6

bob?.department?.head?.name 와 같이 계층구조의 데이터를 확인할때 사용하면 안전하게 호출이 가능합니다.

다른 예제

val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
    item?.let { println(it) } // prints Kotlin and ignores null
}

// 결과
Kotlin

또한 할당을 할때도 null 일 경우 해당 function이 호출 되지 않도록 처리 됩니다.

// If either `person` or `person.department` is null, the function is not called:
person?.department?.head = managersPool.getManager()

Elvis operator (엘비스 연산자)

앞서서 null 체크 문법을 기억하시나요?

?: 엘비스 머리모양을 하고 있는 연산자라고 해서 엘비스 연산자라고 불리고 있습니다.

만약 왼쪽 값이 null 이라면 엘비스 연산자 뒤에 오는 값을 return 합니다.

// null 체크 
val l: Int = if (b != null) b.length else -1

// 동일 결과 return
val l = b?.length ?: -1

null 체크가 참 쉬워지겠지요?

null 허용된 객체 호출

null 허용된 객체는 일반적으로 호출이 되지 않습니다.

?.(안전한 호출)이나 !!.() 연산자를 이용해서 호출해야 하는데요. !!.의 의미는 null이 아니라는 전제 조건을 설정합니다. 만약 null이면 java.lang.NullPointerException이 발생합니다.

val b: String? = null

b.length
error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

b!!.length
java.lang.NullPointerException

b?.length
res33: kotlin.Int? = null

// 설사 초기 값을 설정했어도 ?. !!. 없이는 호출이 불가능 합니다.
val b : String? = "abc"

b.length
error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
b.length

안전한 캐스팅

다른 형으로 캐스팅시 ClassCastException이 발생할 수 있는데요.

val aInt: Int? = a as? Int

이와 같이 호출을 하면 a가 Int 형이 아니면 null을 리턴 합니다.

nullable 리스트에 대한 처리

val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()

filterNotNull을 이용해서 null을 제외한 리스트를 얻을 수 있습니다.

참고자료

태그