Skip to content

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

@DongLee99

Description

@DongLee99

자바 8 이전

자바 8 이전에는 메서드가 특정 조건에서 값을 반환할 수 없을 때 취할 수 있는 선택지가 두 가지 있었다.

  • 예외
  • null 반환

이 두 방식 모두 허점이 존재한다. 예외는 진짜 예외적인 상황에만 사용 해야 하고, null을 반환하는 경우는 별도의 null 처리 코드가 필요하다.

자바 8 이후

자바 버전 8의 등장 이후 또 하나의 선택지가 생겼다.
**Optional**는 null이 아닌 T타입 참조를 하나 담거나, 혹은 아무것도 담지 않을 수 있다.
옵셔널은 원소를 최대 1개 가질 수 있는 불변 컬렉션이다. 보통은 T를 반환해야 하지만 특정 조건에서는 아무것도 반환하지 않아야 할 때 T 대신 Optional를 반환하도록 선언하면 된다.

  • 예외를 던지는 메서드 보다 사용하기 쉽고, Null을 반환하는 메서드 보다 안전하다.
public static <E extends Comparable<E>> Optinal<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)로 생성했다. Optional.of(value)에 null을 넣으면 NullPointerException을 던지니 주의하자.

  • 옵셔널을 반환하는 메서드에서는 절대 null을 반환하지 말자.

Null을 반환하거나 예외를 던지는 대신 옵셔널 반환을 선택하는 기준

옵셔널은 검사 에외와 취지가 비슷하다. 즉 반환 값이 없을 수도 있음을 API 사용자에게 명확히 알려준다. #7
결과가 없을 수 있으며, 클라이언트가 이 상황을 특별하게 처리해야 한다면 Optional를 반환한다.

// 옵셔널 활용1 - 기본값을 정해둘 수 있다.
String lastWordInLexicon = max(words).orElse("단어 없음...");

// 옵셔널 활용2 - 원하는 예외를 던질 수 있다.
Toy myToy = max(toys).orElseThrow(TemperTantrumException::new);

// 옵셔널 활용3 - 항상 값이 채워져 있다고 가정한다.
Element lastNobleGas = max(Elements.NOBLE_GASES).get();

// 옵셔널 활용4 - 옵셔널의 여부를 true / false로 반환해줌
boolean check = parentProcess.isPresent();

반환 값으로 옵셔널을 사용한다고 무조건 득이 되는 건 아니다.

컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안 된다.
빈 Optional<List>를 반환하기보다는 빈 List를 반환하는 게 좋다. #27

추가

박싱된 기본 타입을 담는 옵셔널은 기본 타입 자체보다 무겁다. 따라서 자바에는 int, long, double 전용 옵셔널 클래스들을 준비해놨다.

  • OptionalInt
  • OptionalLong
  • OptionalDouble

옵셔널을 맵의 값으로 사용하지 마라!
옵셔널을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하는 게 적절한 상황은 거의 없다.

정리

갑을 반환하지 못할 가능성이 있고, 호출할 때마다 반환값이 없을 가능성을 염두에 둬야하는 메서드라면 옵셔널을 반환해야 할 상황일 수 있다.
성능에 민감하다면 null을 반환하거나 예외를 던지는게 나을 수 있다.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions