자바 버전 8이 되면서 Optional<T> 을 이용해 보통은 T를 반환해야 하지만

 

특정조건에서는 아무것도 반환하지 않을 수 있게 되었다.

//컬렉션에서 최대값을 구하는 메소드

public static <E extends Comparable<E>> E max(Collection<E> c) {
    if(c.isEmpty()) {
        throw new IllegalArgumentException("빈 컬렉션");
    }

    E result = null;
    for(E e : c) {
        if(result == null || e.compareTo(result) > 0) {
            result = Objects.requiredNonNull(e);
        }
    }

    return result;
}
//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.requiredNonNull(e);
        }
    }

    return Optional.of(result);
}
  • 빈 옵셔널은 Optional.empty()로 생성
  • 값이 든 옵셔널은 Optional.of(value)로 생성
    • Optional.of에 null을 넣으면 NullPointerException 던짐
    • 던지고 싶지 않다면 Optional.ofNullable(value) 사용
    • 옵셔널을 반환하는 메소드에서는 절대 null을 반환하지 말 것

 

 

스트림의 종단 연산중 상당수가 옵셔널을 반환함

//컬렉션에서 최대값을 구하여 Optional<E>로 반환 - 스트림 버전

public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) {
    return c.stream().max(Comparator.naturalOrder());
}

 

 

옵셔널을 사용하는 이유는?

  • 옵셔널은 검사 예외와 취지가 비슷함
  • 반환 값이 없을수도 있음을 API사용자에게 알려주는 것
  • 메소드가 옵셔널을 반환하면 클라이언트는 값을 받지 못했을 때를 대비해야한다
    • 그 중 하나는 기본값 설정이다.
//옵셔널 활용1 - 기본값 세팅

String lastWordInLexicon = max(words).orElse("단어 없음...");
//옵셔널 활용2 - 예외 던지기

Toy myToy = max(toys).orElseThrow(TemperTantrumException::new);
//옵셔널 활용3 - 항상 값이 채워져 있다고 가정

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

 

 

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

  • 컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안된다.
  • 빈 Optional<List<T>> 를 반환하는 것 보다 빈 List<T> 를 반환하는 것이 낫다
  • 결과가 없을 수 있으며, 클라이언트가 이 상황을 특별하게 처리할때만 옵셔널을 반환한다.
  • 옵셔널도 엄연히 객체이고 기본타입보다 무거울 수 밖에 없다.
    • 그래서 자바 API 설계자는 int, long, double 전용 옵셔널을 추가했다.
      • OptionalInt, OptionalLong, OptionalDouble
  • 옵셔널을 컬렉션의키, 값, 원소나 배열의 원소로 사용하는게 적절한 상황은 거의 없음

+ Recent posts