Java Optional 값 안전하게 추출하는 방법

Optional 값 접근 시 주의사항

Optional<T>는 값의 존재 여부를 명시적으로 표현하는 컨테이너입니다. 값이 없는 상태에서 강제로 접근하면 다음 예외가 발생합니다:

NoSuchElementException: No value present

따라서 값 추출 시 get()을 즉시 호출하는 것은 위험합니다. 상황에 맞는 대안 메서드를 선택해야 합니다.

방식 1: 존재 확인 후 접근

Optional<String> username = Optional.of("bob");

if (username.isPresent()) {
    System.out.println("사용자: " + username.get());
}

isPresent()(Java 8+)와 isEmpty()(Java 11+)로 상태를 먼저 확인할 수 있습니다. 다만 이 방식은 여전히 get() 호출이 필요하므로 더 나은 대안이 있습니다.

방식 2: 예외 발생 방식으로 값 보장

Optional<String> email = Optional.of("bob@example.com");
String verified = email.orElseThrow(); // Java 10+

값이 없으면 NoSuchElementException을 던집니다. 사용자 정의 예외도 지정 가능합니다:

String verified = email.orElseThrow(
    () -> new RuntimeException("이메일 정보 누락")
);

방식 3: 대체 값 제공

즉시 생성: orElse()

Optional<String> config = Optional.empty();
String setting = config.orElse("production"); // 항상 "production" 객체 생성

지연 생성: orElseGet()

String setting = config.orElseGet(() -> loadDefaultConfig()); // 필요시에만 실행

대체 값 생성 비용이 클 때 orElseGet()을 사용하면 불필요한 연산을 피할 수 있습니다.

방식 4: 대체 Optional 연결

Optional<String> primary = fetchFromPrimary();
Optional<String> finalValue = primary.or(() -> fetchFromSecondary());

System.out.println(finalValue.orElse("none")); // secondary 결과 또는 "none"

Java 9의 or()은 여러 후보를 연쇄적으로 탐색할 때 유용합니다:

String result = fromRedis()
    .or(() -> fromDatabase())
    .or(() -> fromFile())
    .orElse("unavailable");

함수형 처리 연산

메서드용도
map(Function)값 변환 후 Optional로 감싸 반환
flatMap(Function)이미 Optional을 반환하는 함수와 조합
filter(Predicate)조건 불만족 시 빈 Optional 반환
ifPresent(Consumer)값 존재 시 동작 실행
ifPresentOrElse(Consumer, Runnable)Java 9, 존재/부재 모두 처리
Optional<Integer> score = Optional.of(85);

score.filter(s -> s >= 60)
     .map(s -> "합격: " + s + "점")
     .ifPresent(System.out::println); // "합격: 85점"

score.filter(s -> s < 60)
     .ifPresentOrElse(
         s -> System.out.println("재시험"),
         () -> System.out.println("통과")
     );

안티패턴: 직접 get() 사용

Optional<String> token = Optional.empty();
String t = token.get(); // ❌ 런타임 예외 위험

선택 가이드

상황권장 메서드
반드시 값이 있어야 함orElseThrow()
기본값으로 대체 가능orElse() / orElseGet()
다른 소스에서 대체 탐색or()
값 변환 및 체이닝map(), flatMap(), filter()
부수 효과만 필요ifPresent(), ifPresentOrElse()

설계 원칙

  • 메서드 반환 타입으로만 Optional을 사용하고, 필드나 매개변수에는 적용하지 않습니다
  • 직렬화가 필요한 클래스에는 Optional 필드를 포함하지 않습니다
  • Optional<List<T>> 대신 빈 리스트를 반환하는 것이 더 명확합니다

태그: java Optional Stream API null safety Java 8

7월 8일 16:23에 게시됨