Language/Java

[Java] orElse vs orElseGet

by Donghwan 2021. 10. 29.

orElse와 orElseGet은 T 타입의 값을 반환한다는 것은 동일합니다. 한마디로 Default 값을 설정하는 함수라고 할 수 있습니다. 하지만 같은 기능으로 동작하지만 파라미터와 동작 방식에서 차이를 보입니다. 시나리오를 부여하여 특정 상황에 걸리는 시간을 기준으로 두 메서드의 차이를 알아보겠습니다. 이번 테스트에는 JMH을 사용해서 걸리는 시간을 확인 해보겠습니다. 테스트 조건은 동일한 워밍업 테스트 5번 후 실제 테스트를 5번 진행하는 방식을 기준으로 작성해보도록 하겠습니다.

 

1.  Optional Value Not Null이 아닐 때, 새로운 인스턴스를 반환하는 경우

orElse
@Benchmark
public void orElseInitValueExist(Blackhole blackhole) {
    blackhole.consume(Optional.of(new Donghwan()).orElse(getRandomName()));
}

//result
Benchmark                          Mode  Cnt   Score   Error  Units
orElseInitValueExist               avgt    5  65.552 ± 8.172  ns/op
orElseGet
@Benchmark
public void orElseGetInitValueExist(Blackhole blackhole) {
    blackhole.consume(Optional.of(new Donghwan()).orElseGet(() -> getRandomName()));
}

//result
Benchmark                          Mode  Cnt   Score   Error  Units
orElseGetInitValueExist            avgt    5   3.377 ± 0.345  ns/op​

 

2. Optional Value Is Null일 때, 새로운 인스턴스를 반환하는 경우

orElse
@Benchmark
public void orElseInitValueNotExist(Blackhole blackhole) {
    blackhole.consume(Optional.empty().orElse(getRandomName()));
}

//result
Benchmark                          Mode  Cnt   Score   Error  Units
orElseInitValueNotExist            avgt    5  64.623 ± 3.177  ns/op​
orElseGet
@Benchmark
public void orElseGetInitValueNotExist(Blackhole blackhole) {
    blackhole.consume(Optional.empty().orElseGet(() -> getRandomName()));
}

//result
Benchmark                          Mode  Cnt   Score   Error  Units
orElseGetInitValueNotExist         avgt    5  64.205 ± 3.340  ns/op

 

 

3. Optional Value Not Null일 때,  기존에 존재하는 인스턴스를 반환하는 경우

orElse
@Benchmark
public void orElseInitValueExist(Blackhole blackhole) {
    blackhole.consume(Optional.of(new Donghwan()).orElse(donghwan));
}

//result
Benchmark                          Mode  Cnt  Score   Error  Units
orElseInitValueExist               avgt    5  3.321 ± 0.099  ns/op
orElseGet
@Benchmark
public void orElseGetInitValueExist(Blackhole blackhole) {
    blackhole.consume(Optional.of(new Donghwan()).orElseGet(() -> donghwan));
}

//result
Benchmark                          Mode  Cnt  Score   Error  Units
orElseGetInitValueExist            avgt    5  3.296 ± 0.115  ns/op​

 

4. Optional Value  Is Null일 때, 기존에 존재하는 인스턴스를 반환하는 경우

orElse
@Benchmark
public void orElseInitValueNotExist(Blackhole blackhole) {
    blackhole.consume(Optional.empty().orElse(donghwan));
}

//result
Benchmark                          Mode  Cnt  Score   Error  Units
orElseInitValueNotExist            avgt    5  2.661 ± 0.020  ns/op​
orElseGet
@Benchmark
public void orElseGetInitValueNotExist(Blackhole blackhole) {
    blackhole.consume(Optional.empty().orElseGet(() -> donghwan));
}
//result
Benchmark                          Mode  Cnt  Score   Error  Units
orElseGetInitValueNotExist         avgt    5  2.275 ± 0.072  ns/op​

 

실험결과

두 메서드는 특정 시나리오를 제외하면 전체적으로 비슷한 결과를 가집니다. 당연할 수 있지만 새로운 인스턴스를 만들어 반환하는 것 보다 이미 존재하는 인스를 반환하는 것이 가장 빠르고, 새로운 인스턴스를 생성해야할 경우 orElseGet을 사용하는게 빠르다고 볼 수 있습니다.

왜 orElseGet이 더 빠른지 분석을 해보자면 두 메서드의 파라미터에 차이가 있습니다. orElse는 Default로 주입할 값을 항상 가지고 있어야하는 메서드이지만 orElseGet은 해당 메서드를 구하는 람다를 가지고 있기 때문입니다. orElse는 Optional.value가 존재하더라도 Null을 대비해 Default Value를 항상 가지고 있어야 한다면 orElseGet은 Optional.value가 존재하지 않는 경우에만 Default Value를 구하는 람다가 실행됩니다. 즉, 이미 값이 존재하는 경우에는 Default Value를 구하는 로직이 실행되지 않습니다.

여기서 이 메서드들을 구분해서 사용해야할 진짜 이유가 존재합니다. 만약 orElse에서 새로운 인스턴스를 생성하게 된다면 매번 많은 비용이 드는 new 연산을 실행해야 합니다. 이로 인해 성능의 저하를 가져올 수 있습니다. 그렇기 때문에 이미 Default Value가 존재하는 경우는 Default Value와 orElse를 사용하는 것이 좋습니다. 또 새로운 객체를 생성하거나 새로운 연산을 수행하는 경우에는 orElseGet을 사용하는 것이 좋습니다.

 


참고자료

 

 

728x90
반응형

'Language > Java' 카테고리의 다른 글

[Java] String의 불변성( Immutable )  (0) 2021.11.01
[Java] 동일성과 동등성 ( == vs equals )  (0) 2021.11.01
[Java] Optional  (0) 2021.10.29
[Java] 연산자 ( Operator )  (0) 2021.10.23
[Java] 변수 (Variable)  (0) 2021.10.16

댓글