옵셔널을 반환하면 예외를 던지는 메서드보다 유연하고 사용하기 쉬우며, null을 반환하는 메서드 보다 오류 가능성이 작다.
Optional.empty(), Optional.of(value), Optional.ofNullable(value)
옵셔널을 반환하는 메서드에서는 절대 null을 반환하지 말자.
옵셔널은 검사 예외와 취지가 비슷하다.
클라이언트가 Optional을 대처하는 방법.
• 기본값을 설정한다. • 상황에 맞는 예외를 던진다. • 곧바로 값을 꺼내 사용한다
// 반환 타입으로 Optional<T> 사용하기 (327-328쪽)
public class Max {
// 코드 55-1 컬렉션에서 최댓값을 구한다. - 컬렉션이 비었으면 예외를 던진다. (327쪽)
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.requireNonNull(e);
return result;
}
// 코드 55-2 컬렉션에서 최댓값을 구해 Optional<E>로 반환한다. (327쪽)
**// null을 return 하므로 anti pattern**
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);
}
// 코드 55-3 컬렉션에서 최댓값을 구해 Optional<E>로 반환한다. - 스트림 버전 (328쪽)
public static <E extends Comparable<E>>
Optional<E> max(Collection<E> c) {
return c.stream().max(Comparator.naturalOrder());
}
public static void main(String[] args) {
List<String> words = Arrays.asList("args", "args2", "args3");
// 코드 55-4 옵셔널 활용 1 - 기본값을 정해둘 수 있다. (328쪽)
String lastWordInLexicon = max(words).orElse("단어 없음...");
System.out.println(lastWordInLexicon);
}
}
isPresent() 대신 map(), filter(), flatMap(), ifPresent() 사용하기.
컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안 된다.
박싱(boxing)된 기본 타입을 담은 옵셔널을 반환하지 않는다.
옵셔널을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하는 게 적절한 상환은 거의 없다.
옵셔널은 결과가 없을 수 있으며, 클라이언트가 이 상황을 특별하게 처리해야 한다 면 Optional<T>를 반환한다.
// 불필요하게 사용한 Optional의 isPresent 메서드를 제거하자. (329쪽)
public class ParentPid {
public static void main(String[] args) {
ProcessHandle ph = ProcessHandle.current();
// isPresent를 적절치 못하게 사용했다.
Optional<ProcessHandle> parentProcess = ph.parent();
~~System.out.println("부모 PID: " + (parentProcess.isPresent() ?
String.valueOf(parentProcess.get().pid()) : "N/A"));~~
// 같은 기능을 Optional의 map를 이용해 개선한 코드
**System.out.println("부모 PID: " +
ph.parent().map(h -> String.valueOf(h.pid())).orElse("N/A"));**
// p329 Optional의 스트림 - anti pattern
~~Stream<Optional<String>> streamOfOptionals = Stream.of(~~
Optional.of("Apple"),
Optional.empty(),
Optional.of("Banana"),
Optional.of("Cherry"),
Optional.empty()
);
**// isPresent를 적절치 못하게 사용했다.**
streamOfOptionals.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println);
**// 같은 기능을 Optional의 스트림을 이용해 개선한 코드
streamOfOptionals.flatMap(Optional::stream)
.forEach(System.out::println);**
}
}