[이펙티브 자바] 아이템 55. 옵셔널 반환은 신중히 하라

June·2022년 3월 3일
0

[이펙티브자바]

목록 보기
50/72

자바 8이전에는 메서드가 특정 조건을 반환할 수 없을 때

  1. 예외 반환
  2. null 반환

을 했다. 하지만 각각 문제점이 있다.

  1. 예외는 진짜 예외적인 상황에서만 사용해야 한다 (아이템 69). 예외를 생성할 때 스택 추적 전체를 캡처하므로 비용이 비싸다.
  2. 별도의 null 처리 코드를 추가해야 한다. 그것도 null을 반환하게 한 실제 원인과는 상관 없는 코드에서.

자바 8부터는 Optional<T>가 생겼다. null이 아닌 T타입 참조 하나를 담거나, 혹은 아무것도 담지 않을 수도 있다. 옵셔널은 원소를 최대 1개 가질 수 있는 '불변' 컬렉션이다.

보통은 T를 반환해야 하지만 특정 조건에서는 아무것도 반환하지 않아야할 때 T 대신 Optional<T>를 반환하도록 선언하면된다. 옵셔널을 반환하는 메서드는 예외를 던지는 메서드보다 유연하고 사용하기 쉬우며, null을 반환하는 메서드보다 오류 가능성이 작다.

컬렉션에서 최대값을 구해 Optional<E>로 반환한다.

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) > )
            result = Objects.reuqireNonNull(e);
    return Optional.of(result);
}

빈 옵셔널은 Optional.empty() 로 만들고, 값이 든 옵셔널은 Optional.of(value)로 생성했다. Optional.of(value)에 null을 넣으면 NullPointerException을 던지니 주의하자. null 값도 허용하는 옵셔널을 만들려면 Optional.ofNullable(value)를 사용하면 된다. 옵셔널을 반환하는 메서드에서는 절대 null을 반환하지말자. 옵셔널을 쓸 이유가 없다.

null 반환이나 예외 반환 대신 옵셔널 쓰는 이유는 반환 값이 없을 수도 있음을 API 사용자에게 명확히 알려준다라는 점이다.

메서드가 옵셔널을 반환한다면 클라이언트는 값을 받지 못했을 때 취할 행동을 선택해야 한다. 그중 하나는 기본값을 설정하는 방법이다.

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

상황에 맞는 예외를 던질수도 있는데, 아래 코드에서 실제 예외가 아니라 예외 팩터리를 건내고 있다. 이러면 예외가 실제로 발생하지 않는 한 예외 생성 비용은 들지 않는다.

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

기본값을 설정하는 비용이 부담스럽다면 Supplier<T> 를 인수로 받는 orElseGet을 사용하면 값이 처음 필요할 때 Supplier<T>를 사용해 생성하므로 초기 설정 비용을 낮출 수 있다.

isPresent메서드는 옵셔널이 채워져있으면 true를, 비워져있으면 false를 반환한다. 하지만 앞의 다른 메서드들로 거의 대처할 수 있으므로 신중히 쓰자.

항상 옵셔널을 써야하는건 절대 안디ㅏ. 컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안된다.Optional<List<T>>>를 반환하기보다는 빈 List<T>를 반환하는게 좋다.

결과가 없을 수 있으며, 클라이언트가 이 상황을 특별하게 처리해야 한다면 Optional<T>를 반환한다.

Optional도 엄연히 새로 할당, 초기화해야 하는 객체이고, 그 안에서 값을 꺼내려면 메서드를 호출해야하니 성능이 중요한 상황이면 안 맞을 수도 있다.

박싱된 기본 타입을 담는 옵셔널은 기본 타입 자체보다 무겁다. 그래서 OptionalInt, OptionalLong, OptionalDouble과 같은 것들이 있으니 박싱된 기본 타입을 담은 옵셔널을 반환하지 말자.

옵셔널은 맵의 값으로 사용하면 절대 안된다. 그러면 키가 없다는 사실을 나타내는 경우가 두 가지가 된다. 하나는 키 자체가 없거나 다른 하나는 키는 있지만 속이 빈 옵셔널인 경우다. 그래서 옵셔널을 컬렉션의 키, 값, 원소내 배열의 원소로 사용하는게 적절한 상황은 거의 없다.

0개의 댓글