Java 8부터 도입된 Optional 클래스는 null 관련 오류를 예방하고, 값의 존재 여부를 보다 명확하게 표현할 수 있게 도와줍니다. Optional의 사용 예제와 함께 orElseThrow 메서드를 활용하여 예외 처리를 하는 방법, 그리고 흔히 발생하는 실수에 대해 다뤄보겠습니다.
아래 두 코드 예제를 비교해보겠습니다.
Product product = productRepository.findById(Math.toIntExact(productId))
.orElseThrow(() -> new NullPointerException("해당 상품이 존재하지 않습니다."));
findById는 Optional<Product>를 반환합니다..orElseThrow(...) 메서드를 사용하여, 만약 Optional 내부에 값이 존재하면 이를 반환하고, 값이 없으면 지정된 예외(여기서는 NullPointerException)를 던집니다.product 변수에는 실제 Product 객체가 안전하게 할당됩니다.try {
Product product1 = productRepository.findById(Math.toIntExact(folderId));
} catch (Exception e) {
throw new NullPointerException("해당 상품 존재 않음");
}
findById는 Optional<Product>를 반환합니다.Optional을 직접 Product 타입의 변수에 할당하려고 시도하기 때문에 타입 불일치(컴파일 에러)가 발생합니다.findById는 값이 없을 경우 예외를 던지지 않고 Optional.empty()를 반환하므로, try-catch 블록으로는 적절한 예외 처리를 할 수 없습니다.요약:
첫 번째 코드는Optional을 올바르게 언래핑(unwrapping)하여 실제 객체를 얻는 반면, 두 번째 코드는Optional을 그대로 객체 변수에 할당하려고 하여 컴파일 단계에서 문제가 발생합니다.
orElseThrow 메서드란?orElseThrow는 Optional 내부의 값을 안전하게 가져오거나, 값이 존재하지 않을 때 지정된 예외를 발생시키는 메서드입니다.
Optional<Product> optionalProduct = productRepository.findById(productId);
Product product = optionalProduct.orElseThrow(() -> new NullPointerException("해당 상품이 존재하지 않습니다."));
optionalProduct에 값이 있다면, product 변수에 그 값이 할당됩니다.NullPointerException이 던져집니다.public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
T: Optional이 감싸고 있는 실제 값의 타입입니다.Supplier<? extends X> exceptionSupplier: 값이 없을 때 생성할 예외를 제공하는 함수형 인터페이스입니다.exceptionSupplier.get()을 호출해 예외를 생성하고 던집니다.orElseThrow를 사용할까요?명시적인 예외 처리:
Optional.get()은 값이 없을 경우 NoSuchElementException을 던지지만, orElseThrow를 사용하면 보다 구체적인 예외를 던져서 문제의 원인을 명확하게 할 수 있습니다.
코드 가독성 향상:
조건문 없이 한 줄로 값의 존재 여부와 예외 처리를 할 수 있어 코드가 간결해집니다.
안전성 보장:
값을 사용하기 전에 반드시 존재 여부를 체크함으로써 런타임의 NullPointerException을 예방할 수 있습니다.
public User getUserById(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId));
}
findById 메서드는 Optional<User>를 반환하고, orElseThrow를 사용하여 값이 없을 경우 UserNotFoundException을 발생시킵니다.Java의 Optional과 orElseThrow를 올바르게 활용하면 코드의 안정성과 가독성을 높일 수 있습니다.
orElseThrow를 통해 Optional 내부 값을 안전하게 추출합니다.Optional 자체를 실제 객체에 할당하려는 시도를 방지합니다.