Java 8 Optional 제대로 사용하기
문제 상황
레거시 프로젝트를 Java 8로 마이그레이션하면서 Optional을 적극 도입했다. 하지만 코드 리뷰 중 다음과 같은 패턴을 자주 발견했다.
Optional<User> user = userRepository.findById(id);
if (user.isPresent()) {
return user.get().getName();
}
return null;
이건 Optional을 쓰는 의미가 없다. null 체크를 isPresent()로 바꾼 것뿐이다.
올바른 사용법
1. map과 orElse 활용
String name = userRepository.findById(id)
.map(User::getName)
.orElse("Unknown");
2. orElseThrow로 명확한 예외 처리
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
3. ifPresent로 side-effect 처리
userRepository.findById(id)
.ifPresent(user -> emailService.sendWelcome(user.getEmail()));
안티패턴
Optional을 필드로 사용하지 말 것
// 나쁜 예
public class User {
private Optional<String> middleName;
}
Optional은 직렬화를 지원하지 않고, 메모리 오버헤드가 있다. 필드는 nullable로 두고 getter에서만 Optional로 감싸 반환하는 게 낫다.
Optional.of()와 Optional.ofNullable() 구분
// null이 절대 아닐 때
Optional.of(value) // null이면 NPE 발생
// null 가능성이 있을 때
Optional.ofNullable(value)
결론
Optional은 반환 타입으로 사용할 때 가장 효과적이다. null을 반환하는 대신 Optional.empty()를 반환하면 호출자가 값의 부재를 명시적으로 처리하게 된다. 팀 컨벤션에 이 내용을 추가했다.