널이 될 수 있는 타입
자바와 마찬가지로 코틀린의 참조 값에는 아무것도 참조하지 않을 경우를 나타내는 null이라는 값이 존재합니다. 코틀린 타입 시스템에는 널 값이 될 수 있는 참조 타입과 널 값이 될 수 없는 참조 타입을 구분할 수 있어 컴파일 시점에 NullPointerException(NPE) 가능성을 상당 부분 줄여줍니다.
코틀린에서는 기본적으로 모든 참조 타입은 널이 될 수 없는 타입입니다. 따라서, String 같은 타입에 null을 대입할 수 없습니다. 코틀린에서는 널이 될 수 있는 값을 받는 함수를 작성하려면 아래와 같이 파라미터 타입 뒤에 물음표(?)를 붙여 널이 될 수 있음을 명시해주어야 합니다.
fun isBooleanString(s: String?) = s == "false" || s == "true"
fun main() {
val str = "false"
isBooleanString(str)
}
- 기본적으로 널이 될 수 있는 타입은 원래 타입(?가 붙지 않은 타입)의 상위 타입이기 때문에, 위와 같이 String 타입을 String? 타입에 넣을 수 있습니다.
코틀린 컴파일러는 널이 될 수 없는 값을 표현하기 위해 어떤 래퍼(예를 들어, 자바 8의 Optional 클래스)도 사용하지 않기 때문에, 런타임에 추가 비용이 들지 않습니다.
널이 될 수 있는 타입은 원래 타입에 들어있는 어떤 프로퍼티나 메소드도 제공하지 않습니다. 따라서 아래와 같이 멤버 함수를 호출하거나 프로퍼티를 읽는 등의 연산 시, 오류가 발생합니다.
널 가능성과 스마트 캐스트(smart cast)
널이 될 수 있는 값을 처리하는 가장 직접적인 방법은 해당 값을 조건문을 사용해 null과 비교하는 것입니다.
널이 될 수 있는 값이 null인지 검사하게 되면, 위와 같이 정상 작동을 하게 됩니다. 이는, 스마트 캐스트(smart cast)라고 불리는 코틀린 기능이 작용했기 때문입니다. 기본적으로 null에 대한 동등성 검사를 수행하면, 컴파일러는 코드 흐름의 가지 중 한쪽에서는 대상 값이 확실히 null이고 다른 가지에서는 확실히 null이 아님을 알 수 있게 됩니다. 이 정보를 토대로 컴파일러는 값 타입을 세분화하여 널이 될 수 있는 값을 널이 될 수 없는 값으로 타입 변환(cast)해줍니다.
- 스마트 캐스트는 널 가능성에만 제한되지 않으며, 이 내용은 이후에 다루도록 하겠습니다.
스마트 캐스트가 일어나려면 대상 변수의 값이 검사 지점과 사용 지점 사이에 변하지 않는다고 컴파일러가 확신할 수 있어야 합니다. 이로 인해 가변 프로퍼티(var)에 대해서는 스마트 캐스트를 적용할 수 없습니다.
- 가변 프로퍼티여도 아래 오른쪽 예시처럼 확실하게 null일 수 없는 경우라면, 스마트캐스트가 발생하긴 합니다.
널 아님 단언 연산자
널 아님 단언 연산자는 !! 연산자이며, NullPointerException을 유발할 수 있는 연산자입니다. 이 연산자가 붙은 타입은 null이 아니니 해당 타입의 프로퍼티나 메소드를 제공해도 된다는 의미의 연산자입니다. 널 아님 단언 연산자를 사용하는 것은 컴파일러의 경고를 무시하는 것이기 때문에, 코드 제어 흐름을 고쳐 컴파일러가 스마트 캐스트를 적용할 수 있게 하는 편이 좋습니다.
안전한 호출 연산자
널이 될 수 있는 타입에 대해 널이 될 수 없는 타입에 사용될 프로퍼티나 메소드를 사용하고 싶다면, 안전한 호출 연산(safe call)을 사용해 볼 수 있습니다. 아래와 같이 . 대신 ?.을 사용하면 안전한 호출 연산자를 사용할 수 있습니다.
- 위 3가지 함수는 모두 동일한 로직을 수행합니다.
- 안전한 호출 연산자(?.)는 수신 객체(왼쪽 피연산자)가 null이 아닌 경우 일반적인 함수 호출처럼 작동하며, null인 경우는 해당 함수를 호출하지 않고 null을 돌려줍니다.
엘비스 연산자
널이 될 수 있는 값을 다룰 때 유용한 연산자로 널 복합 연산자(null coalescing operator, :?)를 들 수 있습니다. 이 연산자를 이용하면 null을 대신할 디폴트 값을 지정할 수 있습니다. 이러한 널 복합 연산자를 엘비스 연산자라고 부릅니다.
참고 자료
'PROGRAMMING LANGUAGE > KOTLIN' 카테고리의 다른 글
[Kotlin]enum class와 data class (0) | 2022.08.25 |
---|---|
[Kotlin] 객체 (0) | 2022.08.25 |
[Kotlin] 클래스 기초 (0) | 2022.08.12 |
[Kotlin] 코틀린 함수 (0) | 2022.08.04 |
[Kotlin] 코틀린 언어 기초 (0) | 2022.08.04 |