Java

Optional -2

goodbye 2023. 1. 18. 16:24

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