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

카테고리 없음

[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()

아래 예시 코드를 통해 두 메서드의 차이에 대해 알아보겠습니다.

 

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