Java 8에서 도입된 클래스로 값이 존재하지 않을수도 있는 상황을 명시적으로 처리하기 위해 사용합니다.
Optional 객체 생성하기
- Optional.of(value): 값이 반드시 존재할 때 사용합니다. 값이 null이면 NPE가 발생합니다.
- Optional.ofNullable(value): nullable한 값을 감싸 Optional 객체를 생성할 때 사용한다.
Optional 객체에서 값 획득하기
- get() 호출: 값을 바로 가져오기 시도한다. 값이 존재하면 반환하지만, 없으면 NoSuchElementException이 발생
- isPresent() → get(): 값의 존재 여부를 확인하고 가져오는 방식으로 사용 / 일반적인 null 체크와 다를 게 없으므로, Optional의 효용이 떨어질 수 있다.
- orElse(T other): 값이 있으면 가져오고, 없으면 other를 가져온다. / 즉시평가
- orElseGet(Supplier<? extends T> supplier): 값이 있으면 가져오고, 없으면 supplier를 호출해 생성 & 반환 / 지연평가
- orElseThrow(): 값이 있으면 가져오고, 없으면 지정한 예외를 던진다.
orElse() vs orElseGet()
아래 예시 코드를 통해 두 메서드의 차이에 대해 알아보겠습니다.
JAVA
public class OptionalTest {
public static void main(String[] args) {
System.out.println("== orElse ==");
String result1 = getOptionalValue().orElse(getHeavyResource());
System.out.println("\n== orElseGet ==");
String result2 = getOptionalValue().orElseGet(() -> getHeavyResource());
}
private static Optional<String> getOptionalValue() {
return Optional.of("123");
}
private static String getHeavyResource() {
try {
// cost 높은 호출을 가정
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "123,000";
}
}
// java.util.Optional
public final class Optional<T> {
// 생략
/**
* If a value is present, returns the value, otherwise returns
* {@code other}.
*
* @param other the value to be returned, if no value is present.
* May be {@code null}.
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
/**
* If a value is present, returns the value, otherwise returns the result
* produced by the supplying function.
*
* @param supplier the supplying function that produces a value to be returned
* @return the value, if present, otherwise the result produced by the
* supplying function
* @throws NullPointerException if no value is present and the supplying
* function is {@code null}
*/
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
// 생략
}
- orElse(): Optional 내에 값이 있어도 getHeavyResource() 메서드가 호출된다. (값을 즉시 평가)
- orElseGet(): Optional 내에 값이 없는 경우에만, supplier.get()을 통해 getHeavyResource() 메서드가 호출한다. (값을 지연 평가)
위와 같은 차이로, side-effect가 발생할 수 있거나, 호출에 cost가 높은 메서드는 orElseGet()을 사용하는 것이 훨씬 유리하다.
주의하기
- 멤버 변수로 사용하지 않기
- Optional 멤버 변수 자체가 null로 할당될 수 있음. => null을 피하려했는데 NPE를 만나게 됨
- 매개변수로 사용하지 않기
- 호출자 측이 null을 전달하고 싶은 경우 => null과 의미 상 큰 차이 없지만 비용이 높은 Optional.empty()를 사용해야 함
Optional은 메서드의 리턴(반환)값이 없을수도 있는 경우를 제한적으로 표현하기 위해 설계되어 위 내용을 주의해 사용하는 것이 좋다.
※ Optional JavaDoc
Optional (Java Platform SE 8 )
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl
docs.oracle.com