코틀린의 가장 큰 특징은 컴파일 단계에서 NullPointerException(NPE)을 방지하도록 설계되었다는 점이다.
코틀린은 타입 추론을 지원하지만, null을 대입할 때는 이야기가 다르다.
var name = null // (X) 컴파일러가 타입을 추론할 수 없음
어떤 타입의 Null인지 알 수 없기 때문에, Null을 허용하려면 반드시 명시적 타입 지정과 함께 ? 키워드를 붙여야 한다.
var name : String? = null // (O)
name = "John Doe"
String?과 String은 서로 다른 타입이다가장 흔히 하는 착각이 String?을 단순히 String에 null이 추가된 상태로 보는 것이지만, 코틀린에서 이 둘은 완전히 다른 타입으로 취급된다.
Java와 비교해보자, Java 에서는 래퍼클래스와 기본 타입이 존재한다.
예시를 들어보자면 Java에서는 정수를 표기할 때 Integer 와 int 를 사용할 수 있는데
두 타입은 null의 허용 여부를 보여주는 단편적인 예시이다.
Integer num1 = null; int num2 = 0; num2 = num1; // 오류 발생! (언박싱 과정에서 NPE 위험)이처럼 코틀린에서도
null이 가능한 타입(String?)의 값을null이 불가능한 타입(String)에 그냥 대입할 수는 없다.
!!를 사용하면 Nullable 타입을 Non-Null 타입으로 강제로 바꿀 수 있다.
var name : String? = null
var name2 : String = name!! // "내가 책임질게, 무조건 null 아니야!"
name이 실제로 null이라면 런타임에 에러가 발생한다. 이는 개발자의 책임이며, 가급적 사용을 지양해야 하는 좋지 않은 방법이다.?.let { } 사용 (권장)코틀린이 제공하는 가장 세련된 방법 중 하나다.
의미: "null이 아니면(
?.) 다음 내용을 실행하자(let { })"
fun main() {
var name : String? = "John Doe"
var name2 : String = ""
name?.let {
name2 = it // it은 null이 아닌 name을 가리킴
}
}
?.)과 엘비스 연산자(?:)?. (Safe Call): null이면 뒤의 코드를 실행하지 않고 바로 null을 반환한다.?: (Elvis Operator): null일 경우 지정한 기본값을 대신 사용한다.val length = name?.length ?: 0 // name이 null이면 0을 반환
?: 이 변수는 null일 수도 있음을 선언.String? ≠ String: 둘은 엄격히 다른 타입이므로 직접 대입 불가.?.let: null이 아닐 때만 안전하게 코드를 수행하는 가장 코틀린스러운 방법.!!: 강제로 null이 아님을 선언하지만, NPE 위험이 커서 권장하지 않음.?.: null이면 실행하지 않음 (Safe Call)?:: null이면 이 값을 대신 사용함 (Elvis Operator)