Rlog

Kotlin 에서 Null 을 다루기 본문

Kotlin

Kotlin 에서 Null 을 다루기

dev_roach 2022. 1. 18. 19:02
728x90

이 예제는 코틀린 쿡북을 읽고 정리한 내용입니다.

아래와 같은 클래스가 하나 존재한다고 해보자.

class Person(
  val first: String,
  val middle: String?,
  val last: String,
)

코틀린에는 Nullable(null 을 허용) 이라는 개념이 존재한다.
왜 이런 개념이 필요하지? 라는 의문을 가질 수 있는 사람이 분명 있을 것이기에 간단하게 짚고 넘어가려고 한다.
Nullable 을 도입하는 이유는 Null 로 부터 더 안전해지기 위해서이다.

예를 들어 A 라는 변수에 Null 이 대입될 수 있다고 해보자.
자바같은 경우에는 A 라는 변수에 Null 이 들어갈 수 있다는 것을 런타임에 되서야 알 수 있을 것이다.
그렇게 되면 우리는 NullPointerException 을 맞이하게 된다.

하지만 Kotlin 에서는 A 라는 변수에 Null 값이 들어갈 수 있다는 것을 컴파일 시간에 알 수 있다.
이는 컴파일때부터 NullPointerException 을 방지할 수 있음을 의미한다.
자세한건 아래코드를 한번 보자.

fun test1() {
  val name: String
  val name2: String?

  // 아래와 같이 null 을 할당하면 컴파일이 되지 않음
  //  name = null
  name2 = null

}

위와 같이 ? 를 붙이지 않은 name 변수에는 null 을 할당할 수 없다.
Null 이 허용되지 않는 변수라고 명시적으로 선언해줬기 때문이다.
그와반대로 Null이 허용되는 변수라고 선언해준 name2 의 경우에는 Null 의 대입이 가능하다.
만약 우리가 name2 를 이용한다면 반드시 Null-Check 를 하게 된다.
이로서 Null 값에 대한 처리가 가능한 것이다.
아래 코드를 한번보자

class Person(
  val first: String,
  val middle: String?,
  val last: String,
)

fun test2() {
  val p = Person(
    first = "North",
    middle = null,
    last = "West"
  )

  if (p.middle != null) {
    // smart cast!
    val middleNameLength = p.middle.length
  }

}

Person Class 의 middle 값은 명시적으로 Null 이 허용되는 property 이다.
따라서 우리가 p.middle.length 를 사용하기 위해서는 반드시 Null 체크를 해주어야 한다.
본문에서는 if 문을 통해서 Null-Check 를 진행하고 있다.

만약 위와 같이 if 를 통해 Null-Check 를 하게 되면 아래 스코프에서는 Smart Cast 가 되어 Null 값이 아닌 객체로 사용된다.
되게 편한 기능인데 아마도 IDE가 제공해주는 기능일 것이다. (?)
여하튼 근데 var 로 할경우에는 smart cast 가 되지 않는다.
그 이유는 중간에 값이 바뀔 수도 있다고 판단하기 때문이다.
아래 예시를 한번보자.

fun test3() {
  var p = Person(
    first = "North",
    middle = null,
    last = "West"
  )

  if (p.middle != null) {
    // not smart cast! var 를 사용할 경우에는 smart cast 가 되지 않는다.
    // val middleNameLength = p.middle!!.length

    // 다만 not-null assertion operator 는 NullPointerException 을 유발할 수도 있으므로 ? 연산자를 이용하자
    val middleNameLength = p.middle?.length
  }

따라서 var 의 경우에는 자신이 코드를 보고 Null 에 대한 안전한 처리를 진행해주면 되는데
예를 들면 위의 경우와 같이 !!(not-null assertion operator) 을 이용해줘도 되고 ? 연산자를 이용해줘도 된다.
다만 !! 의 경우 null 일 경우 NullPointerException 을 마주할 것이다.
내 생각에 코틀린의 장점은 Null-Safety 인데 !! 를 쓰는건 좋은 방향은 아니라고 생각한다.
? 연산자의 경우에는 null 일 경우 null 을 리턴해준다.

위의 경우 엘비스 연산자를 통하면 좀더 안전하게 처리할 수 있는데 바로 아래와 같은 방식으로 말이다.

fun test4() {
  var p = Person(
    first = "North",
    middle = null,
    last = "West"
  )

  if (p.middle != null) {
    // not smart cast! var 를 사용할 경우에는 smart cast 가 되지 않는다.
    // val middleNameLength = p.middle!!.length

    // 다만 not-null assertion operator 는 NullPointerException 을 유발할 수도 있으므로 ? 연산자를 이용하자
    val middleNameLength = p.middle?.length ?: 0
  }

}

이렇게 할 경우 기본적으로 0 이 리턴되어 좀 더 안전한 처리가 가능하다.
삼항식과 비슷하다고 생각하면 편하다.

Kotlin 은 Null-Safety 하기 위해 많은 기능을 제공한다.
Java 에서는 Optional 을 사용해야 했지만 Kotlin 에서는 그럴필요가 없다.
Nullable 에 대한 개념자체가 언어의 기본 스펙이다.
이를 잘 이용해서 NullPointerException 을 피해보자!

'Kotlin' 카테고리의 다른 글

Kotlin 의 확장함수가 좋은 이유  (0) 2022.03.18
Ko-Test Framework 사용해보기  (0) 2022.01.21
[Kotlin Spring] Logger 를 간편하게  (0) 2021.12.14
[Mac] Kotlin 설치 및 CLI 에서 사용하기  (0) 2021.12.06
Kotlin Null 처리  (0) 2021.11.18