Optional은 Java8부터 지원하는 클래스이다. 이는 NPE(NullPointExcetption)
을 방지하기 위해 각종 메소드들을 제공한다.
NPE는 null을 사용할 경우 발생하는 오류로 이를 방지하기 위해 null검사를 먼저 해야 한다. 또는 null 대신 초기값을 사용하기를 권장한다.
List<String> names = getNames();
names.sort(); // names가 null이라면 NPE가 발생함
List<String> names = getNames();
// NPE를 방지하기 위해 null 검사를 해야함
if(names != null){
names.sort();
}
Optional을 사용하면 NPE를 방지할 수 있다. Optional이 null이 올 수 있는 값을 감싸는 Wrapper 클래스로 동작하여 null을 참조하여도 NPE가 발생하지 않는다.
public final class Optional<T> {
// If non-null, the value; if null, indicates no value is present
private final T value;
...
}
Optional은 Wrapper 클래스이기 때문에 값이 없을 수도 있는데, 이때 Optional.empty()로 생성할 수 있다
Optional<String> optional = Optional.empty();
System.out.println(optional); // Optional.empty
System.out.println(optional.isPresent()); // false
Optional 클래스는 내부에서 static 변수로 EMPTY 객체를 미리 생성해서 가지고 있다. 이러한 이유로 빈 객체를 여러 번 생성해줘야 하는 경우에도 1개의 EMPTY 객체를 공유함으로써 메모리를 절약한다.
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
...
}
만약 어떤 데이터가 절대 null이 아니라면 Optional.of()로 생성할 수 있다. 만약 Optional.of()로 Null을 저장하려고 하면 NullPointerException이 발생한다.
// Optional의 value는 절대 null이 아니다.
Optional<String> optional = Optional.of("MyName");
만약 어떤 데이터가 null이 올 수도 있고 아닐 수도 있는 경우에는 Optional.ofNullbale로 생성할 수 있다. 그리고 이후에 orElse 또는 orElseGet 메소드를 이용해서 값이 없는 경우라도 안전하게 값을 가져올 수 있다.
// Optional의 value는 값이 있을 수도 있고 null 일 수도 있다.
Optional<String> optional = Optional.ofNullable(getName());
String name = optional.orElse("anonymous"); // 값이 없다면 "anonymous" 를 리턴
Optional은 값을 wrapping하고 다시 푸는 과정이 동반되기 때문에 메소드의 반환값이 절대 null이 아니라면 Optional을 사용하지 않는 것이 좋다.