자바 8 전에는 메서드가 특정 조건에서 값이 없을 경우의 처리를 다음과 같이 하였다.
값이 없는 경우가 예외가 발생해야 하는 경우 라면 예외를 발생시키는 것이 적절할 수 있다. 하지만 아니라면 발생시킨 예외를 매번 try-catch 해주어야 한다.
반환값으로 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 는 발생하지 않는다.
빈 값(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 임을 확인하고(값이 존재하지 않을 수도 있음을 확인하고) 그에 따른 처리를 직접 선택할 수 있다.
@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 일때 대체할 수 있는 값을 설정한다. 하지만 두 메서드는 약간의 차이점이 있다.