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
자체를 실제 객체에 할당하려는 시도를 방지합니다.