Null Safety와 엘비스(Elvis) 오퍼레이터

2019. 2. 5. 17:53Programming/Kotlin

반응형

Udacity에서 봤던 강의 중 Elvis Operator이 유용해보이는데, 적절한 사용방법을 찾아보려고 했다. 강의에서는 타입을 설명하는 과정에서 나온 내용이었는데, Kotlin Reference에는 Ohter의 Null Safety페이지에 위치해있다. 아래의 내용은 내가 이해하여 정리한 내용으로, 자세하고 정확한 내용은 Kotlin Reference > Ohter > Null Safety 페이지를 참조하도록 하자.

Nullable 타입과 Non-Null 타입

Kotlin에는 Null을 가질 수 있는 타입과, Null을 가질 수 없는 타입이 존재한다. 예를 들어서 일반적인 경우 String은 null을 할당받을 수 없다.

var a: String = "abc"
a = null // compilation error

null을 할당하기 위해서는, String?처럼 뒤에 ?를 붙임으로써, nullable string 타입을 선언할 수 있다.

var b: String? = "abc"
b = null // ok
print(b)

조건문에서의 Null 체크

위에서 선언한 a는 null을 가질 수 없는 문자열 타입이므로, a.length와 같이 property를 직접 참조하더라도 NullPointerException의 걱정은 없다. 하지만 b의 경우에는 null을 가질 수 있기 때문에, b.length와 같이 property를 직접 참조하는 경우 NullPointerException의 위험이 있다. 이런 경우 조건문을 통해 null 체크를 해서, NullPointerException을 방지할 수 있다.

val l = if (b != null) b.length else -1

안전한 호출(Safe Call)

조건문을 사용하지 않고 Null체크를 할 수 있는 방법이 있다. Safe call operator를 사용하는 것이다. ?.을 사용하여 호출하면, 간단하게 Null체크를 하는게 가능하다.

val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length)

b?.length에서 b가 null일 경우, b?.length는 null을 반환한다.

Safe call은 값을 할당을 할 때도 사용할 수 있다. 아래의 코드를 살펴보자.

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

할당하려는 값의 safe call 체인(이 코드에서는 person, department) 중, 하나의 값만 null이어도 managersPool.getManager()의 결과값이 할당되지 않는다.

엘비스 오퍼레이터(Elvis Operator)

엘비스 오퍼레이터 ?:는 삼항연산자 같은 녀석이다. 아래의 코드를 살펴보자.

val l = b?.length ?: -1

위의 코드는 ‘b?.lengthl에 할당하려고 하는데, b?.length가 null이면 -1l에 할당해줘.’라는 의미이다. 여기서 -1b?.length의 값이 null일때만 할당된다는 점에 주의하자. 엘비스 오퍼레이터는 굉장히 유용하다. ?:의 모습이 마치 엘비스 프레슬리처럼 보여서 엘비스 오퍼레이터라고 부른다. Kotlin의 은근히 귀여운 포인트가 아닐까.

!! 오퍼레이터

NullPointerException을 발생시켜야 할 필요가 있다면, !! 오퍼레이터를 사용하는 방법도 있다. 아래의 코드를 살펴보자.

val l = b!!.length

b!!.lengthbnull이 아닐 경우에는, b의 값을 l에 할당하게 된다. 하지만 bnull일 경우에는, NullPointerException을 발생시킨다.

안전한 형변환(Safe Cast)

할당하려는 값의 타입이 일치하지 않는 경우, 일반적으로는 ClassCastException이 발생한다. Safe cast를 사용하면 값을 할당하지 못하는 경우, 할당하려는 값 대신 null을 할당할 수 있다. 아래의 코드를 살펴보자.

val aInt: Int? = a as? Int

위의 값에서 aInt형이 아니라면, aInt에는 null이 할당된다.

반응형