[아이템 55] 옵셔널 반환은 신중히 하라

Jimin Lim·2023년 7월 6일
0

Effective Java

목록 보기
38/38
post-thumbnail

아이템 55

옵셔널 반환은 신중히 하라

자바 8 이전에는 값을 반환할 수 없을 때 (1) 예외 던지기, (2) null 반환 방식이 있었다. (1)의 경우, 진짜 예외적인 상황에서만 사용해야 하고 예외를 생성할 때 스택 추적 전체를 캡처해야 하므로 비용이 만만치 않다. (2)의 경우는 클라에서 별도의 null 처리 코드를 추가해야 하고 만약 무시한다면 NPE가 터질 수 있다.

자바8에서는 Optinal<T>이 생기게 되었다. 옵셔널을 반환하는 메서드는 예외를 던지는 메서드보다 유연하고 사용하기 쉬우며, null을 반환하는 메서드보다 오류 가능성이 적다.

✅ Optional 예시

public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) {
    if(c.isEmpty()) {
	    return Optional.empty();
    }
    
    E result = null;
    for(E e : c){
        if(result == null || e.compareTo(result) > 0){
            result = Objects.requireNonNull(e);
        }
    }
    
    return Optional.of(result);
}
  • Optional.empty(): 빈 옵셔널 반환
  • Optional.of(value): 값이 든 옵셔널, null을 넣으면 NPE
  • Optional.ofNullable(value): null값도 허용하는 옵셔널
  • Objects.reuqireNonNull(value): value가 null이면 예외

Optional로 반환한다면, 클라에서 취할 수 있는 방법은 다음과 같다.

1) 기본값 정하기

String lastWordInLexicon = max(words).orElse("단어없음");

2) 원하는 예외 던지기

Toy myToy = max(toys).orElseThrow(TemperTantrumException::new);

3) 항상 값이 채워져 있다고 가정

Element lastNobleGas = max(Elements.NOBLE_GASES).get();

4) isPresent

"Parent PID: " + (parentProcess.isPresent() ? String.valueOf(parentProcess.get().pid()) : "N/A")

5) map

ph.parent().map(h -> String.valueOf(h.pid())).orElse("N/A"));

6) 스트림 filter

streamOfOptionals
        .filter(Optional::isPresent)
        .map(Optional::get)

7) flatMap

streamOfOptionals
        .flatMap(Optional::stream)
  • Optional::stream: Optional에 값이 있으면 그 값을 원소로 담은 스트림으로, 없으면 빈 스트림

✅ Optional 주의점

1) 컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안된다.
또다시 옵셔널에 대한 처리를 클라에서 해야한다.

2) 결과가 없을 수 있고, 클라가 이 상황을 특별히 사용해야 한다면 Optional<T>사용
Optional을 새로 할당하고 초기화하고 그 안에서 값을 꺼내려면 한 단계가 더 필요하다. 따라서 성능이 중요하다면 옵셔널이 맞지 않을 수 있다.

3) 박싱된 기본 타입을 담은 옵셔널을 반환하는 일은 없도록 하자
int, long, double 전용 옵셔널 클래스인 OptionalInt, OptionalLong, OptionalDouble이 존재 한다.

4) Map의 키로 쓰지말자
map의 키로 쓴다면 맵 안에 키가 없다는 사실을 나타내는 경우가 두 가지가 된다. (1) 키 자체가 없는 경우, (2) 키가 있지만 그 키 속이 빈 옵셔널인 경우.
더 일반화해서, 옵셔널을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하는 게 적절한 상황은 거의 없다.

✅ 결론

반환 값이 없는 메서드라면 옵셔널을 반환해야할 수도 있다. 하지만 옵셔널 반환에는 성능 저하가 뒤따르므로 null이나 예외를 던지는 편이 나을 수 있다. 그리고 옵셔널을 반환값 이외의 용도로 쓰는 경우는 매우 드물다!

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글