널 안정성 (Null Safety)

NullPointerException

널 안정성 (Null Safety)

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
essential