NullPointerException (NPE)
자바에서 객체를 참조하려고 하는 경우에 그 객체가 null
이라면 throw
로 예외가 발생하는 에러이다.
예를 들어, String
타입의 변수에 null
을 대입하고, 그 변수에 대해서 length()
메소드를 호출하였을 경우에 NullPointerException
이 발생한다.
자바에서 null 안전
원시적인 방법으로 함수명을 이용하는 방법이 있다.
private String getNameOrNull() { /* ... */ }
어노테이션을 달고 정적 분석 도구로 지정하는 방법이 있다.
// null 을 반환할지도 모르는 경우
@Nullable
String getName() { /* ... */ }
// null 을 반환하지 않을 경우
@NotNull
String getName() { /* ... */ }
존재하지 않을 가능성이 있는 값을 null
을 대신해 표현하기 위해 Java
SE
8 에 도입된 Java.util.Optional
클래스를 활용하는 방법이 있다.
Optional
타입은 존재하지 않을 수 있는 값과 절대적으로 존재하는 값을 구별하기 위해 다양하고 유용한 메소드를 제공한다.- 값이 없다면
Optional#empty
로 반환되는 객체를 사용한다. - 값이 있다면
Optional#of
의 파라미터로 값을 전달하여 래핑한다.
자바에서 위와 같은 방법을 사용하는 것은 좋은 방법이긴 하지만 여전히 변수와 메소드의 반환값은 언제나 null
이 될 수 있고 NullPointerException
이 발생할 수 있는 위험이 있다.
import org.springframework.lang.NonNull;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.getName().toString();
}
@NotNull
Optional<String> getName() {
return null;
}
}
// Exception in thread "main" java.lang.NullPointerException
코틀린에서 null 안전
코틀린에서 기본적으로 모든 값은 NotNull
이고, 값을 Nullable
하게 하고 싶다면 타입 뒤에 ?
를 추가하면 된다.
var a: String = "Hello"
a = "Goodbye"
a = null // Comple Error
var a: String? = "Hello"
a = "Goodbye"
a = null // 정상
코틀린에서는 Nullable
값에 대한 참조 시 컴피일 시점에서 에러를 발생시키기 때문에 null
체크를 통해 접근해야한다.
if (str != null) {
println(str.length)
}
안전 호출 (Safe Call)
코틀린에서는 Nullable
값에 대한 참조 시 null
체크를 통해 접근해야 하는데, 이를 간결하게 작성해주는 것이 안전 호출이다.
val str: String? = null
// 안전 호출
val length1: Int? = str?.length
// null 체크
val length2: Int? = if (str != null) str.length else null
!! 연산자
!!
연산자는 Nullable
값을 NotNull
값으로 변환해주는 연산자이다.
fun main() {
val str: String? = "Hello"
println(str!!.length)
}
// 5
!!
연산자는 NullPointerException
이 발생할 수 있기 때문에 부득이한 경우를 제외하고는 사용을 권장하지 않는다.
fun main() {
val str: String? = null
println(str!!.length)
}
// Exception in thread "main" java.lang.NullPointerException