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>>대신 빈 리스트를 반환하는 것이 더 명확합니다