Kotlin - Grammar(NULL)

정현철·2023년 4월 15일
0

Android App

목록 보기
2/6
post-thumbnail

Kotlin Docs - Null safety

Nullable value

  • 코틀린에서 일반적인 변수는, null value를 갖지 못하는 것이 default이다.
    • 그래서 특정한 타입에 맞는 method를 부를 때, NPE를 걱정하지 않아도 된다.
  • null이 가능하게 하려면, type name 마지막에 ?를 붙여 명시적으로 null이 가능함을 표기해야 한다.
val str: String = null // 컴파일 에러
val str: String? = null // 가능

// 함수 return type로도 가능.
fun parseInt(str: String): Int? {
	// ...
}

그러나 null의 assign을 의도적으로 막은 것을 해제하였으니, 이러한 nullable variables는 NullPointerException을 주의해야 한다.

  • 예를 들어, 자바에서 null이 담겨 있는 변수에 method를 호출하면 프로그램 자체가 멈춘다.
  • 코틀린에서는 컴파일 에러가 발생한다.
val a: String? = "abc"
a = null
val len = a.length // error: variable "a" can be null

// 그래서 가장 간단하게는, condition으로 제어할 수 있다.
// 아래와 같은 경우, 컴파일러가 null의 가능성이 없음을 이해하고, 에러로 처리하지 않는다.
val len = if (a != null) a.length else -1

Null Safe call operator "?."

위와 같이 condition을 통해 명시하지 않더라도, null이 아닐 때에만 이하 method를 실행하라는 요구를 할 수 있다.

// return b.length if b is not null, and null otherwise.
// 그래서 자동적으로 len의 type는 Int?이다.
val len = a?.length
val bossName = bob?.department?.head?.name // 이렇게 chain이 있을 때에도 사용할 수 있다.

val a = "abc"
println(a?.length) // 이건 필요 없는 safe call이다.

그리고 nullable variable에, null이 아닐 때에만 특정 operation을 실행하려면, let을 사용하면 된다.

val listWithNull: List<String?> = listOf("Kotlin", null)
for (item in listWithNull) {
	item?.let {
    	prinln(it)
    } // let 이하의 block은 item이 null이 아닐 때에만 실행
}
/// kotlin이 한 번만 출력된다.

Elvis operator

nullable reference가 있을 때(a라 하자), "a가 null이 아닐 때에만 a를 쓰고, 아니면 다른 값을 쓰자"라는 코드를 작성하려면 ?:를 쓸 수 있다. 이를 Elvis operator라 한다.

throw와 return도 kotlin에서는 expression이기 때문에, elvis operator의 RHS에 사용될 수 있다.

val l: Int = if (a != null) a.length else -1
// 동일한 표현이다
val l = a?.length ?: -1 // b?.length가 null이 아니라면 b.length를, null이라면 -1을 assign

fun foo(node: Node): String? {
    val parent = node.getParent() ?: return null
    val name = node.getName() ?: throw IllegalArgumentException("name expected")
    // ...
}

Others

"!!" operator

이는 NPE를 발생시키기 위한 operator이다.

  • 지금까지 확인한 것처럼, kotlin에서는 nullable reference에서 특정 method를 호출하는 등, NPE가 발생할 일이 있을 때 컴파일 타임에 컴파일 에러를 통해 제지한다.
  • 이와 다르게, !!는 컴파일 가능하게 두고 NPE를 발생시킬 수 있게 한다는 의미이다.
val l = b!!.length // null 아니라면 b.length, null이라면 NPE 발생

Safe casts "as?"

Regular casts는 객체가 target type이 아닐 경우, ClassCastException을 발생시킬 수 있다.
이때 as?를 사용하면 만약 다른 type을 casting하게 된다고 하더라도, 런타임 에러를 발생시키는 대신 null을 넣어 넘어가 준다.

val aInt: Int? = x as? Int // casting 실패시에도 null로 초기화 (expection이 발생하지 않음)

Collections of a nullable type

non-null elements만 필터링하고 싶은 경우, filterNoNull()을 사용할 수 있다.

val nullableList: List<Int?> = listOf(1, 2, null)
val intList: List<Int> = nullableList.filterNoNull() 
// 1, 2만 담긴다.

0개의 댓글