Effective Java | #55. 옵셔널 반환은 신중히 하라

보람·2022년 5월 15일
0

Effective-Java

목록 보기
21/25

Optional<T>

  • 특정 조건에서 반환할 값이 없을때 취할 수 있는 선택지
  • null이 아닌 T 타입 참조를 하나 하거나, 혹은 아무것도 담지 않거나(비었다)
  • 원소를 최대 1개만 가질 수 있는 불변 컬렉션
  • 옵셔널을 반환하는 메서드는 예외를 던지는 메서드보다 유연하고 사용하기 쉬우며, null을 반환하는 메서드보다 오류 가능성이 적음
public static <E extends Comparable<E>>
Optional<E> max(Collection<E> c) {
    if (c.isEmpty()) //(1)
        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); (2)
}
  • (1) 빈 컬렉션인 경우 throw new IllegalArgumentException("빈 컬렉션");보다는 Optional.empty();을 반환하는게 더 낫다.
  • (2) 빈 컬렉션이 아니라면 해당 값(최댓값)을 반환한다.
  • 옵셔널 반환 메서드는 절대 null을 반환 X
  • 연산 중 상당수가 옵셔널을 반환하는 스트림을 사용하면 좀더 간결하게 옵셔널을 반환하는 코드를 작성할 수 있음
    • 옵셔널을 직접 구현하기 보다 해당 실제 연산에서 옵셔널을 반환하는 stream을 사용해서 위에 코드보다 훨씬 간결해졌다.
public static <E extends Comparable<E>>
Optional<E> max(Collection<E> c) {
    return c.stream().max(Comparator.naturalOrder());
}

옵셔널 반환 함수 사용시 값이 없을 때 선택지

기본값 orElse

  • String lastWordInLexicon = max(words).orElse("단어 없음...");
    • empty를 반환했다면 "단어 없음..."을 받게 됨

예외 던지기 orElseThrow

  • String lastWordInLexicon2 = max(words).orElseThrow(NoSuchElementException::new);

항상 값이 있다고 가정 get

  • String lastWordInLexicon3 = max(words).get();
    • 두번째처럼 똑같이 NoSuchElementException 반환

적합한 메서드를 모르겠다면 isPresent

  • 옵셔널이 채워져 있으면 true, 비어 있으면 false 반환
public static void main(String[] args) {
    //부모 프로세스의 PID를 출력하거나 부모가 없다면 "N/A"를 출력하는 코드
    ProcessHandle ph = ProcessHandle.current();

    // isPresent를 적절치 못하게 사용했다. (1)
    Optional<ProcessHandle> parentProcess = ph.parent();
    System.out.println("부모 PID: " + (parentProcess.isPresent() ?
            String.valueOf(parentProcess.get().pid()) : "N/A")); //부모 PID: 27194

    // 같은 기능을 Optional의 map를 이용해 개선한 코드 (2)
    System.out.println("부모 PID: " +
        ph.parent().map(h -> String.valueOf(h.pid())).orElse("N/A")); //부모 PID: 27194
}
  • (1) 의 내용을 Optional의 map을 사용하면 (2)처럼 다듬을 수 있음, 아래 이미지는 Optional의 map -> 똑같이 isPresent로 검사하고 있다.

이럴때는 옵셔널 사용 지양

  • 컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안됨
    • Optional<List<T>>List<T>로 반환하기(item-54)
  • 박싱된 기본 타입을 담은 옵셔널을 반환하지 말자
    • 값을 두번 감싸기 때문에 기본 타입보다 무거움
  • 필수값을 갖는다면 옵셔널 사용 X, 선택적 필드라면 옵셔널 반환 가능
  • 성능 저하가 뒤따르기 때문에 성능에 민감한 메서드라면 null 반환 or 예외를 던지자

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

profile
백엔드 개발자

0개의 댓글