Optional -2
1. 개요
Optional 사용하면 코드가 Null-Safe 해지고, 메서드 체이닝을 통해 가독성이 좋아지면서 어플리케이션이 안정적이 될 수 있는 장점이 있습니다.
하지만 이러한 장점은 Optional 을 설계한 의도에 맞게 올바르게 사용했을때 해당하는 내용으로 Optional 을 남용하는 경우나 잘못 사용하는 코드는 아래와 같은 부작용이 발생 할 수 있으니 주의해서 사용해야 합니다
2. Optional 의 부작용
2.1 overhead 가능성(시간적, 공간적 비용 증가)
Optional 안의 객체를 얻기 위해서는 Optional 객체를 통해 접근해야 하므로 접근비용이 증가합니다. 그리고 성능테스트 결과 nullables 를 사용하는 접근 방식보다 2~3배 느리다고 합니다
그리고 Optional은 객체를 감싸는 컨네이너이므로 기존의 객체를 저장하기 위한 메모리에 더해 Optional 객체를 저장하기 위한 메모라가 할당되는 것으로 추가적인 메모리를 사용하게 됨으로써 오버헤드가 증가합니다
2.2 또 다른 예외 가능성 (NoSuchElementException)
만약 Optional로 받은 변수를 값이 있는지 판단하지 않고 접근하려고 하면 NoSuchElementException 이 발생합니다
Optional<User> user = userRepository.findAll();
User user = user.get() // user가 null 일경우 NoSuchElementException 발생
Null Safe 하도록 처리하기 위해 Optional 을 사용하였지만, 값의 유무를 확인하지않고 접근하면 NullPointException 은 발생하지않지만 NoSuchElementException 이 발생하는 결과를 낳게됩니다
2.3 Serialize(직렬화) 불가능
Option은 Serialize를 지원하지 않아서 클래스 필드로 사용하는 것은 안티패턴 으로 간주됩니다. 다만 Class Filed 에 Optional 을 사용해도 된다는 의견 도 있으니 관심있는 분은 확인해보셔도 됩니다.
그리고 Optional 은 값 기반 클래스로서 선택 항목의 인스턴스에서 창조 동등성이나 ID 해시코드 또는 동기화등을 사용하면 예측 할 수 없는 결과가 발생 할 수 있다고 공식문서 에서 안내하고 있습니다.
따라서 Serialize(직렬화)가 필요한 캐시나 메세지큐 등과 연동하는것은 피해야합니다.
한편 자바에서 직렬화(serialize) 할 때 Optional 을 반환하는 get Method 를 사용하지 않고 reflection 을 사용해 필드에 직접 접근하기때문에 get method에만 Optional 을 사용하면 좋습니다
2.4 코드의 가독성 저하 가능성
Optional 을 잘못 사용하거나 남용하게 될 경우 코드의 가독성을 해치는 결과를 초래하기도 합니다.
Optional 바람직한 사용
public class ItemService {
// 예외 대신 null을 반환
Item findItemById(Long itemId) {
Optional<Item> item = itemRepository.findById(itemId);
if(item.isPresent()) {
...
return item.get();
}
return null;
}
// 예외 던짐
Item fineItemByIdThrow(Long itemId) {
Optional<Item> item = itemRepository.findById(itemId);
if(item.isEmpty()) {
throw new NoSuchElementException();
}
return item.get();
}
// orElseThrow를 사용하여 코드 가독성 향상!!
Item findItemByIdOrElseThrow(Long itemId) {
return itemRepository.findById(itemId)
.orElseThrow(() -> new NoSuchElementException());
}
}
Optional 잘못 사용
// method로 받는 인자 User 객체가 null 이면 NoSuchElementException 발생할수 있음
public void temp(Optional<User> optionalUser) {
User user = optionalUser.orElseThrow(IllegalStateException::new);
}
Optional 사용으로 가독성 저하
// 객체와 값의 null 두번 체크로 인한 코드 가독성 저하
public void temp(Optional<User> optionalUser) {
if (optionalUser != null && optionalUser.isPresent()) {
}
throw new IllegalStateException();
}
Reference
Uploaded by N2T