Java 8에서 추가된 Optional 의 메서드인 orElseorElseGet 의 차이점을 확인하고자 한다.

java.util.Optional
T orElse(T other)
T orElseGet(Supplier<? extends T> other)

두 메서드의 시그니처를 보면 반환 타입이 같다. 이름에서 나타내듯이 Optional 의 값이 null 일 경우에 인자로 받은 값(T)을 반환하는 메서드이다. 하지만, 서로 다른 파라미터를 전달 받는다. orElse 는 반환할 값을 그대로 받는 반면, orElseGetSupplier 로 랩핑한 값을 인자로 받는다.

이는 함수를 전달받아 바로 값을 가져오지 않고lazy 필요할 때 값을 가져온다. 즉, orElseGetnull 일 경우에만 함수가 실행되면서 인스턴스화되지만, orElse 는 무조건 인스턴스화 된다.

class LocalTest {
    @Test
    public void test1() {
        Optional.ofNullable(null).orElse(new TestObject("1 ")); (1)
        System.out.println();
        Optional.ofNullable(new TestObject("2-1 ")).orElse(new TestObject("2-2 ")); (2)
        System.out.println();
        Optional.ofNullable(null).orElseGet(TestObject::new); (1)
        System.out.println();
        Optional.ofNullable(new TestObject("4-1 ")).orElseGet(TestObject::new); (3)
    }

    class TestObject {
        TestObject() { System.out.print("new"); }
        TestObject(String s) { System.out.print(s == null ? "new" : s); }
    }
}
1
2-1 2-2
new
4-1
  1. ofNullable 의 인자값으로 null 이기 때문에 인스턴스 생성

  2. ofNullable 의 인자값이 null 이 아니지만 new TestObject("2-2 ") 가 실행된다.

  3. ofNullable 의 인자값이 null 이 아니므로 TestObject::new 는 동작하지 않는다

Conclusion

불필요한 호출을 줄이기 위해 null 일 경우 반환할 값이 primitive type이면 orElse(), 객체를 생성해야한다면 orElseGet() 를 사용하면 될 것 같다.

int value = Optional.ofNullable(obj1).orElse(123);
TestObject object = Optional.ofNullable(obj2).orElseGet(() -> new TestObject());
TestObject object = Optional.ofNullable(obj2).orElseGet(TestObject::new);