이끌든지 따르든지 비키든지

카테고리 없음

[Java] Optional

SeongHo5 2025. 3. 14. 22:41

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