본문 바로가기
개발 지식/Java

[Optional] orElse와 orElseGet의 차이

by 에르주 2021. 12. 30.
반응형

실무개발을 진행하면서 자주 썼지만 정확한 차이에 대해 혼동이 있던 것 중 orElse와 orElseGet의 차이에 대해 정리하고자 한다.
우선 orElse와 orElseGet는 Java 8의 Optional 도입과 함께 등장했던 메소드다. 

그 전에 orElseGet를 이해하는데 필요한 Supplier interface에 대해 간단히 정리한다.


Supplier Interface

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

Supplier는 넘겨준 Type T를 그대로 반환하는 함수형 인터페이스이다. 함수형 인터페이스이기 때문에 람다형식으로도 많이 쓰인다.

아래 코드는 String Type으로 변환하는 Supplier Interface를 구현한 예시이다. Override 형식으로 get의 메소드를 구현할수도 있고 lambda 표현식으로도 사용할 수 있다.

@Test
public void testSupplierInterface(){

	System.out.println("============ 인터페이스 Override ============");
	Supplier<String> supplierInterface = new Supplier<String>() {
          @Override
          public String get() {
          return "Supplier Interface !!";
        }
     };

  System.out.println(supplierInterface.get());

  System.out.println("============ 람다 표현식 사용하기 ============");
  Supplier<String> supplierLambda = ()-> "supplier Interface with lambda !! ";
  System.out.println(supplierLambda.get());

}

람다 표현식


그럼 한번 orElse와 orElseGet의 차이를 알아보자.


1. orElse

  public T orElse(T other) {
        return value != null ? value : other;
    }

Optional에서의 orElse값이 null이 아닐 경우 그 해당 값을(Value) 반환하며 null일 경우 Type T를 그대로 반환한다.

@Test
public void testOptionalElse(){

  List<String> examList = Arrays.asList("1","2","3");
  // 3을 찾아라(findAny) -> 있음
  String yesValue = examList.stream().filter(p-> p.equals("3")).findAny().orElse("orElse");
  // 5를 찾아라(findAny) -> 없음
  String noValue = examList.stream().filter(p-> p.equals("5")).findAny().orElse("orElse");

  System.out.println(YesValue);
  System.out.println(noValue);


}

예시 코드를 살펴보면 examList 값에 "3" 과 "5"인 값을 찾는 Stream filter를 구현하였다.
리스트에는 {"1","2","3"} 값이 있기에 "3" 은 찾을 수 있으나 "5"인 값은 찾을 수 없다.

그 결과 값으로는 다음과 같다.

yesValue, noValue

즉 해당 값이 없을 경우 orElse 메소드에 넘겨준 "orElse"로 출력된다.

 


2. orElseGet

public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

Optional에서의 값이 null이 아닐 경우 그 해당 값(Value)을 반환하여 null인 경우에는 Supplier Generice으로 넘겨받았을 때의 값을 반환한다.

Supplier값으로 넘겨주세요.

예시 코드를 보면 String Type를 매개변수로 넘겼을 경우에 에러가 발생한다.
orElseGet 메소드는 Supplier Interface를 활용해야한다.

@Test
public void testOptionalElseGet(){

  List<String> examList = Arrays.asList("1","2","3");

  // 3을 찾아라(findAny) -> 있음
  String yesValue = examList.stream().filter(p-> p.equals("3")).findAny().orElseGet(()->"orElseGet");
  // 5를 찾아라(findAny) -> 없음
  String noValue = examList.stream().filter(p-> p.equals("5")).findAny().orElseGet(()->"orElseGet");
  
  System.out.println(yesExamValue);
  System.out.println(noExamValue);

}

orElseGet

예시코드를 보면 lambda 표현식 () -> "orElseGet" 즉 Supplier Interface 객체를 넘기는 것을 확인 할 수 있다. 


그러면 orElse와 orElseGet의 차이점은 무엇일까?

하나의 예시를 더 살펴보자.

    @Test
    public void testOptionalElse(){

            String notNullTemp ="orElse 테스트 하기";
            String nullTemp ="";

            String resultNullOrElse = Optional.of(notNullTemp).orElse(welcome()); // welcome 함수 실행
            String resultNotNullOrElse = Optional.of(nullTemp).orElse(welcome()); // welcome 함수 실행


            System.out.println("notNullOrElse : " + resultNullOrElse);
            System.out.println("NullOrElse : " + resultNotNullOrElse);

            System.out.println("===============================");

            String resultNullOrElseGet = Optional.of(notNullTemp).orElseGet(this::welcome);
            String resultNotNullOrElseGet = Optional.of(nullTemp).orElseGet(this::welcome);

            System.out.println("notNullOrElseGet : " + resultNullOrElseGet);
            System.out.println("NullOrElseGet : " + resultNotNullOrElseGet);

    }

    public String welcome(){

        System.out.println("ErJuer 블로그에 오신 것을 환영합니다.");
        return "ErJuer 블로그에 오신 것을 환영합니다.";
   }



orElse, orElseGet 차이

결론을 말하자면

orElse         -> Null 값이라도 wlecome 메소드 실행
orElseGet  -> Null 값일 때만 *welcome 메소드 실행함*  // 22.04.04 수정

이다. 

그 이유는 orElseGet은 Supplier Generic으로 래핑되어 있기 때문에 Null값이 아닐 때 인스턴스가 생성되기 때문이다. 
orElseGet은 null인 객체가 넘어온 경우에만 Supplier interface를 사용하여 생성된 값을 반환한다는 뜻이다.

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get(); // get 메소드
    }
}


실무에서 해당 값을 무분별하게 썼었는데 성능 이슈 그리고 Exception 처리를 위해 조금 더 정확히 이해하고 써야겠다.

 

끝. 

반응형

댓글