Optional 클래스
자바 개발자들이 가장 많이 겪는 에러 중 하나가 바로 NullPointerException(NPE) 입니다. 변수가 null인 상태에서 그 변수를 통해 객체 내부의 메서드나 필드에 접근하려 할 때 발생합니다.
자바 8에서는 이런 null 값을 안전하게 다룰 수 있도록 돕는 일종의 "객체 포장지(래퍼, Wrapper)" 클래스인 Optional<T>을 도입했습니다. 보통 스트림 파이프라인의 계산 결과가 값이 없을 수 있는 상황에 많이 사용되며, 단일 데이터의 null 처리에 강력합니다.
1. Optional 객체 생성하기
Optional 객체는 직접 new 키워드가 아니라 정적 팩토리 메서드로 생성합니다.
// 1. 확실히 데이터가 null이 아닐 때
Optional<String> opt1 = Optional.of("Hello!");
// 2. 데이터가 null일 가능성이 있을 때 (가장 많이 씀)
String nullableStr = null;
Optional<String> opt2 = Optional.ofNullable(nullableStr);
// 3. 비어있는(null을 포장한) Optional 만들기
Optional<String> opt3 = Optional.empty();
2. Optional 값 꺼내기 (null 안전하게 처리)
단순히 .get()을 쓰면 내부 값이 null일 때 에러가 발생하므로 Optional을 쓰는 의미가 퇴색됩니다. 안전하게 값을 가져오는 방법들이 제공됩니다.
기본값 제공하기: orElse(), orElseGet()
String name = null;
Optional<String> optName = Optional.ofNullable(name);
// orElse(기본값): 값이 있으면 그 값을 리턴, 없으면 지정한 기본값을 리턴
String resultTarget = optName.orElse("Guest"); // "Guest"
// orElseGet(람다식): 비용이 큰 기본값을 설정할 때 지연 초기화 수행
String result = optName.orElseGet(() -> "Guest user from DB");
예외 던지기: orElseThrow()
값이 존재하지 않을 때 커스텀 예외를 던지고 싶다면 사용합니다. API 서버 등에서 회원을 조회하지 못했을 때 유용합니다.
User user = optUser.orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
값이 있을 때만 실행: ifPresent()
값이 존재할 경우에만 넘겨진 람다식을 실행합니다(Consumer 형식). 값이 없으면 아무 일도 일어나지 않습니다.
Optional<String> emailOpt = Optional.ofNullable("admin@blue.com");
emailOpt.ifPresent(e -> System.out.println("이메일 발송: " + e));
3. 왜 Optional을 남용하면 안 되는가?
Optional은 그 자체로 "객체"이기 때문에 메모리를 소비합니다. 따라서 클래스의 단순 필드나 메서드의 매개변수(parameter)로 선언하는 것은 좋은 프랙티스가 아닙니다 (오버헤드 발생 및 코드 가독성 저하).
가장 이상적인 안티패턴 방지 규칙:
"결과를 반환해야 하지만 null이 결과로 나올 가능성이 높은 메서드의 반환 타입(Return Type) 으로만 사용하라."입니다.