Optional
자바8 부터 Optional을 지원하기 시작했다. Optional은 다음과 같은 시나리오에서 쓰인다. 값을 반환하지 못할 가능성이 있고, 호출할 때마다 반환값이 없을 가능성을 염두에 둬야하는 메소드를 작성할 때 사용한다. Optional을 사용한다면 클라이언트측 코드에 값이 반환되었는지를 알리는 형태가 되니 원인 메소드와 멀리 떨어진 코드에서 NullPointerException이 발생하는 경우를 예방할 수 있다. 다음은 Optional을 사용한 코드이다.
1 | public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) { |
Optional.of(value)
는 null을 넣으면 NullPointerException이 발생하니 주의하자. 만약 null을 허용하는 Optional을 만들고 싶다면 Optional.ofNullable(value)
를 사용하자.
스트림 종단 연산중 상당수가 Optional을 반환한다. 다음은 위 코드를 스트림으로 표현한 코드이다.
1 | public static <E extends Comparable<E>> Optional<E> max(Collection<E> c) { |
Optional의 장점은 클라이언트 측에 값이 없을수도 있다는 것을 알리는 것이다. 그래서 클라이언트 측은 값이 없을 때 처리하는 로직을 작성해야 한다. 다음은 클라이언트 측의 코드 예이다.
1 | //기본 값 설정 |
이따끔 기본값을 생성하는데 비용이 큰 경우가 있다. 그럴때는 Supplier<T>
를 인수로 받는 orElseGet
을 사용하면 된다. Supplier<T>
는 lazy하니 실제 값 사용시에 생성을 하므로 초기 생성 비용을 낮출 수 있다. 더 특별한 쓰임이 필요하다면 filter, map, flatMap, ifPresent를 사용하면 된다.
스트림을 사용한다면 옵셔널들을 Stream<Optional<T>>
로 받아서 그 중 채워진 옵셔널들에서 값을 뽑다 Stream<T>
에 건네는 경우도 있다. 다음 코드는 그 예이다.
1 | streamOfOptionals.filter(Optional::isPresent).map(Optional::get); |
컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸지 말고 빈 컨테이너를 리턴하자. Optional을 사용하는데도 대가가 따른다. Optional도 초기화해야하는 객체이고 그 안에서 값을 꺼내려면 메소드 콜 스택이 한 단계 더 깊어지는 것이다. 그래서 성능이 중요한 곳이라면 옵셔널이 맞지 않을때도 있다. 또한 박싱된 기본 타입을 담는 옵셔널은 무거울 수 밖에 없다. 그럴 때를 위해 OptionalInt, OptionalDouble, OptionalLong을 사용하자.