자바 8 전에는 메서드가 특정 조건에서 값을 반환할 수 없을때 취하는 행동 두가지가 있었다.
1. 예외를 던진다.
2. null값을 던진다.
예외를 던지는 케이스에서는 스택 추적 전체를 캡쳐해야 되고, 진짜 예외적인 케이스에서만 던져야 하므로 문제가 발생할 수도 있고, null로 반환할 시 클라이언트 단에서 무조건 null 체크를 해줘야 된다는 단점이 있었다.
자바 8 이후에는 Optional<T>
가 생겨서 이 타입을 반환한다고 선언했을 때
public static <E extends Comparable<E>> E max(Collection<E> c){
if(c.isEmpty()) throw new IllegalArgumentException("empty Collection");
E result = null;
for(E e : c)
if(result == null || e.compareTo(result) >0)
result = Objects.requireNonNull(e);
return result;
}
이제 max 함수를 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.requireNonNull(e);
return Optional.of(result);
}
그리 어렵지 않게 구현이 가능하다.
public static <E extends Comparable<E>> Optional<E> max(Collection<E> c){
return c.stream().max(Comparator.naturalOrder());
}
스트림의 종단연산 중 상당수가 optional을 반환하도록 할 수 있다.
옵셔널은 반환값이 없을 수도 있음을 API 이용자에게 알려주는 역할을 한다.
String lastWordInLexicon = max(words).orElse("단어없음...");
Toy myToy= max(toys).orElseThrow(TemperTantrumException::New);
Element lastNobleGas= max(toys).get();
Optional<ProcessHandle> parentProcess = ph.parent();
System.out.println("parent PID "+(parentProcess.isPresent() ?
String.valueOf(parentProcess.get().pid()) : "N/A");
하지만 이렇게 isPresent를 사용한 경우에는 앞서 언급한 메서드들로 대체할 수 있고, 짧고 명확한 코드를 생산할 수 있다.
streamOfOptionals
.filter(Optional::isPresent)
.map(Optional::get)
옵셔널에 값이 있으면, 그 값을 꺼내 스트림에 매핑하는 함수이다.
OptionalInt
, OptionalLong
, OptionalDouble
을 제공하므로 이걸 사용하자.