콘텐츠로 이동

orElse() VS orElseGet()

orElse() VS orElseGet()

차이점 한 줄 요약

orElse(T)항상 인자를 평가하고, orElseGet(Supplier<T>)는 값이 없을 때만 평가한다. 인자로 비용이 큰 연산(DB 조회, 객체 생성 등)을 넘길 때 orElse를 사용하면 불필요한 실행이 발생한다.


왜 구분해야 하는가?

겉보기엔 동일해 보이지만 실행 시점이 다르다. 인자로 비용이 큰 연산을 넘기면 성능 차이가 발생한다.

Optional<String> opt = Optional.of("존재하는 값");

opt.orElse(heavyOperation());          // heavyOperation() 항상 실행됨
opt.orElseGet(() -> heavyOperation()); // 값이 있으므로 실행 안 됨

값이 있음에도 orElseheavyOperation()을 호출한다.


비교

구분 orElse(T) orElseGet(Supplier<T>)
인자 타입 값 직접 전달 Supplier (람다) 전달
평가 시점 항상 즉시 평가 (Eager) 값이 없을 때만 평가 (Lazy)
값이 있을 때 인자 평가 후 무시 인자 평가 자체를 안 함
값이 없을 때 인자 반환 Supplier 실행 결과 반환
적합한 인자 상수, 이미 생성된 객체 메서드 호출, 객체 생성, DB 조회

언제 orElse를 쓰는가

인자가 상수이거나 이미 생성된 객체일 때. 어차피 평가 비용이 없으므로 차이가 없다.

opt.orElse("기본값");           // 문자열 리터럴 — 비용 없음
opt.orElse(0);                  // 기본 정수 — 비용 없음
opt.orElse(Collections.emptyList()); // 이미 존재하는 싱글톤 — 비용 없음

언제 orElseGet을 쓰는가

인자가 새 객체 생성, 메서드 호출, DB 조회 등 비용이 있는 연산일 때.

// 새 객체 생성
opt.orElseGet(() -> new User("guest"));

// 다른 메서드 호출
opt.orElseGet(() -> userRepository.findDefault());

// 복잡한 연산
opt.orElseGet(() -> {
    String name = config.getDefaultName();
    return name.toUpperCase();
});

실수하기 쉬운 패턴

// 문제: 값이 있어도 새 객체가 매번 생성됨
Optional<User> opt = Optional.of(existingUser);
User result = opt.orElse(new User("guest")); // new User()가 항상 실행됨

// 해결
User result = opt.orElseGet(() -> new User("guest")); // 값 없을 때만 생성
// 문제: 값이 있어도 DB를 매번 조회함
User result = opt.orElse(userRepository.findDefault()); // DB 쿼리 항상 실행

// 해결
User result = opt.orElseGet(() -> userRepository.findDefault()); // 값 없을 때만 조회

정리

  • 인자가 상수·리터럴orElse
  • 인자가 연산·생성·IOorElseGet
  • 확신이 없으면 orElseGet이 안전하다