# 1. Optional.ofNullable() / Optional.empty() / Optional.of()
Optional 객체 생성 메서드는 Optional.ofNullable
, Optional.empty
, Optional.of
3가지가 정적 팩토리 메서드가 있습니다.
어떤 입력으로 Optional 객체 생성이 필요할 때, 입력 값이 null 이 될 수 있을 경우를 고려한다면 이 3가지 중 어떤 메서드를 통해 Optional 생성을 해야할까요?
당연히 메서드 명에서 알 수 있듯이 Optional.ofNullable
을 사용하는 것이 맞을텐데요,
만약 의도치 않게 다른 메서드를 통해 Optional 객체를 생성하고 바로 메서드 체이닝을 사용하게 된다면 어떻게 되는지 알아보겠습니다.
String outputOfNullable = Optional.ofNullable(null)
.map(s -> "foo")
.orElse("bar"); // Result: "bar"
String outputOfEmpty = Optional.empty()
.map(s -> "foo")
.orElse("bar"); // Result: "bar"
String outputOfInput = Optional.of(null)
.map(s -> "foo")
.orElse("bar"); // RuntimeException
ofNullable() 메서드는 입력값이 null 일때는 empty() 메서드를 통해 생성한 Optional 을 반환하기 때문에 outputOfNullable 과 outputOfEmpty 의 결과 값("bar") 은 같습니다. 즉, 코드에서 표현한 메서드 체이닝이 생각대로 처리됩니다.
하지만 of() 메서드의 경우는 컴파일 에러는 나지 않지만 of() 메서드 실행 시 NPE 이 발생하면서 메서드 체이닝이 실행되지 않습니다. 이렇게 Optional 생성을 잘못 사용할 경우 기대한 결과 대신 RuntimeException 이 발생할 수 있으므로 주의하여 사용해야 합니다.
# 2. orElse(), orElseGet()
Optional 의 내부 객체 값이 비어있을 때 orElse()
또는 orElseGet()
를 사용하는데요,
이 두 메서드는 동작 방식에 차이가 있습니다.
Optional<Date> foo = Optional.empty();
Date bar1 = foo.orElse(new Date());
Date bar2 = foo.orElseGet(Date::new);
orElse() 메서드는 인스턴스 객체를 인자로 받기 때문에 foo 가 비어있는지 여부와 상관없이 항상 인스턴스 객체 생성이 필요합니다.
orElseGet() 메서드는 메서드 레퍼런스를 인자로 받고 있으며 foo 가 실제로 비어있을 때만 인스턴스 객체를 생성합니다.
즉, Lazy 하게 사용하려면 orElseGet() 을 사용하는게 좋습니다.