자바 8 전에는 메서드가 특정 조건에서 값이 없을 경우의 처리를 다음과 같이 하였다.

1. 예외 발생

값이 없는 경우가 예외가 발생해야 하는 경우 라면 예외를 발생시키는 것이 적절할 수 있다. 하지만 아니라면 발생시킨 예외를 매번 try-catch 해주어야 한다.

2. null 반환

반환값으로 null 을 준다면 이 메서드를 사용하는 모든 곳에서 널처리를 추가로 해주어야 한다. 그렇지 않으면 NPE(NullPointerException) 이 발생할 수 있다.

값이 없더라도 예외를 발생시키지 않아야 하고 NPE 을 피하기 위해서 Optional 을 사용할 수 있다. Optional 은 자바 8 에서 추가되었으며 값이 존재할 수도 있고 아닐 수도 있을 때 사용한다.

public final class Optional<T> {
    private static final Optional<?> EMPTY = new Optional<>();

    private final T value;

    private Optional() {
        this.value = null;
    }

		// 생략
}

Optional 은 다음과 같이 객체를 감싸는 객체이다. 값이 없을 경우 null 을 저장한다. 반환하려는 값이 null 이더라도 객체로 한 번 감쌌기 때문에 NPE 는 발생하지 않는다.

Optional 객체 생성

빈 값(null) 을 저장하고 싶을 때에는 empty() 를 사용한다.

@DisplayName("빈 객체를 생성한다.")
@Test
void empty() {
    Optional<Object> test = Optional.empty();

    assertThat(test.isEmpty()).isTrue();
}

값을 저장하려 할 때는 of() 를 사용한다. of() 에 전달하는 값은 null 이 아니어야 한다. null 일 경우 NPE 가 발생한다.

@DisplayName("값이 있는 객체를 생성한다.")
@Test
void of() {
    Optional<String> test = Optional.of("");

    assertThat(test.isPresent()).isTrue();
}

@DisplayName("of() 에 null 을 추가할 경우 예외가 발생하는지 확인한다.")
@Test
void ofException() {
    assertThatThrownBy(() -> Optional.of(null))
            .isInstanceOf(NullPointerException.class);
}

null 인지 아닌지 모르는 값을 저장할 때는 ofNullable() 을 사용한다. ofNullable() 에 전달하는 값은 null 이어도 된다.

@DisplayName("값이 있는 객체를 생성한다.")
@Test
void ofNullable() {
    Optional<String> test = Optional.ofNullable("");

    assertThat(test.isPresent()).isTrue();
}

@DisplayName("ofNullable() 에 null 을 넣어 객체를 생성한다.")
@Test
void ofNullableNull() {
    Optional<String> test = Optional.ofNullable(null);

    assertThat(test.isEmpty()).isTrue();
}

Optional 에 저장된 값 활용

메서드를 사용하는 사용자가 반환값이 Optional 임을 확인하고(값이 존재하지 않을 수도 있음을 확인하고) 그에 따른 처리를 직접 선택할 수 있다.

기본값 설정

@DisplayName("값을 가져온다.")
@Test
void orElse() {
    Optional<String> words = Optional.empty();

    String word = words.orElse("");

    assertThat(word).isEqualTo("");
}

@DisplayName("값을 가져온다.")
@Test
void orElseGet() {
    Optional<String> words = Optional.empty();

    String word = words.orElseGet(() -> "");

    assertThat(word).isEqualTo("");
}

orElse()orElseGet() 은 모두 Optional 객체에 담긴 값이 null 일때 대체할 수 있는 값을 설정한다. 하지만 두 메서드는 약간의 차이점이 있다.