Optional이란?
Optional은 Java 8부터 추가된 클래스로, ‘값이 있을 수도 있고 없을 수도 있다’는 개념을 명시적으로 표현하기 위해 사용됩니다. 전통적으로 Java에서 메서드가 ‘값이 없을’ 경우에는 null을 반환하거나 예외를 던져 왔습니다. 그러나 이러한 방식은 NullPointerException(NPE)의 위험이나 ‘이 메서드가 null을 반환할 수 있다’는 사실을 코드만으로는 명확히 알기 어렵다는 문제가 있었습니다.
Optional을 사용하면 다음과 같은 이점이 있습니다.
- 명시적 표현
- ‘값이 없을 수도 있음’을 Optional이란 반환 타입만으로도 알 수 있어 코드 가독성과 안정성이 향상됩니다.
- 메서드 반환 타입이 Optional<T>라면, 그 메서드 호출 결과가 null이 될 수도 있음을 암묵적으로 알 수 있게 됩니다.
- null 처리 로직 간소화
- null 체크를 직접 하기보다는 ifPresent, orElse, orElseThrow 등의 메서드를 사용하여 간결하게 처리할 수 있습니다.
- 이를 통해 NullPointerException 발생 가능성을 줄이고, 코드가 보다 함수형 스타일을 따르게 됩니다.
- 함수형 스타일 메서드 체이닝
- map, flatMap, filter 같은 고차 함수들을 사용할 수 있어, 값의 존재 여부를 확인하는 반복적인 if (x != null) 구문을 대체할 수 있습니다.
언제 Optional을 사용해야 할까?
- ‘반환할 값이 있을 수도 없을 수도 있음’을 명확히 표현해야 하는 경우
- 예) findById 메서드처럼 DB나 컬렉션에서 어떤 값을 찾는데, 그 값이 존재하지 않을 수도 있는 상황에서 결과를 담는 경우.
- API 설계 단계에서 메서드가 null이 될 가능성을 명시하고자 할 때
- 메서드에서 null을 반환할 수 있다는 사실을 주석이 아닌 타입 자체로 전달해, 오용 가능성을 줄일 수 있습니다.
- 값의 부재를 예외 상황으로 보고 싶지 않은 경우
- 예외를 던져야 할 수준은 아니지만, 그냥 null을 반환하기엔 직관적이지 않을 때 Optional을 사용합니다.
언제 사용하지 않아야 할까?
- 필드(멤버 변수)로 쓰지 말 것
- Optional은 ‘값이 있을 수도, 없을 수도 있는 객체’를 표현하기 위한 것이지, 엔티티나 DTO의 필드를 선언할 때 쓰는 용도로 만들어진 것이 아닙니다.
- 필드에 Optional을 두면 직렬화/역직렬화에서 문제가 생길 수 있고, 불필요한 레퍼 객체가 중첩되어 성능이 저하될 수 있습니다.
- 메서드 파라미터로 사용 지양
- 파라미터에 Optional을 사용하기보다는 오버로딩, 기본값 설정, Builder 패턴 등을 사용하는 것이 더 권장됩니다.
- 컬렉션을 담는 Optional
- “값이 없을 수도 있음”을 표현해야 하는 상황에서 컬렉션 자체가 이미 ‘비어 있음(empty) 또는 있음’을 표현할 수 있습니다. Optional<Collection<T>>를 사용하기보다는 빈 컬렉션을 반환하거나 null 이외의 다른 방법으로 처리하는 편이 좋습니다.
public class UserService {
private final Map<Long, User> userStore = new HashMap<>();
// Optional을 통한 반환
public Optional<User> findUserById(Long id) {
return Optional.ofNullable(userStore.get(id));
}
public void printUserName(Long id) {
Optional<User> maybeUser = findUserById(id);
// ifPresent: 값이 있으면 람다 실행
maybeUser.ifPresent(user -> System.out.println(user.getName()));
// orElse: 값이 없으면 대체값 사용
User user = maybeUser.orElse(new User("익명"));
System.out.println("유저명: " + user.getName());
// orElseThrow: 값이 없으면 예외 던지기
User userOrException = maybeUser.orElseThrow(() -> new IllegalArgumentException("유저를 찾을 수 없습니다."));
System.out.println("필수 유저명: " + userOrException.getName());
// map: 값이 있으면 변환
String userName = maybeUser.map(User::getName).orElse("No Name");
System.out.println("User Name: " + userName);
}
}
'프로그래밍언어 > JAVA' 카테고리의 다른 글
Virtual Thread(가상 스레드) (0) | 2024.09.01 |
---|---|
hashcode와 equals (0) | 2024.08.05 |
Hibernate ? (0) | 2024.03.31 |
순수 JAVA JPA (0) | 2024.03.17 |
getDeclaredConstructor().newInstance()? (0) | 2024.03.16 |