Java Optional – orElse() vs orElseGet() – Java Optional – orElse() vs orElseGet()

最后修改: 2018年 5月 17日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

The API of Optional typically has two methods that can cause confusion: orElse() and orElseGet().

Optional的API通常有两个方法,会引起混淆。orElse() orElseGet()

In this quick tutorial, we’ll look at the difference between these two and explore when to use each one.

在这个快速教程中,我们将看一下这两者之间的区别,并探讨何时使用每一种方法。

2. Signatures

2.签名

First, let’s start with the basics by looking at their signatures:

首先,让我们从基本知识开始,看一下他们的签名。

public T orElse(T other)

public T orElseGet(Supplier<? extends T> other)

Clearly, orElse() takes any parameter of a type T, whereas orElseGet() accepts a functional interface of type Supplier that returns an object of type T.

显然,orElse() 接受任何T类型的参数,orElseGet() 接受一个Supplier 类型的功能接口,返回T类型的对象。

Based on their Javadocs:

基于他们的Javadocs

  • orElse(): returns the value if present, otherwise returns other
  • orElseGet(): returns the value if present, otherwise invokes other and returns the result of its invocation

3. Differences

3.差异

It’s easy to be a bit confused by these simplified definitions, so let’s dig a little deeper and look at some actual usage scenarios.

我们很容易被这些简化的定义所迷惑,所以让我们深入挖掘一下,看看一些实际的使用场景。

3.1. orElse()

3.1. orElse()

Assuming we have our logger configured properly, let’s start with writing a simple piece of code:

假设我们已经正确配置了记录器,让我们从编写一段简单的代码开始。

String name = Optional.of("baeldung")
  .orElse(getRandomName());

Notice that getRandomName() is a method which returns a random name from a List<String>of names:

注意,getRandomName()是一个方法,从List<String>名字中返回一个随机的名字

public String getRandomName() {
    LOG.info("getRandomName() method - start");
    
    Random random = new Random();
    int index = random.nextInt(5);
    
    LOG.info("getRandomName() method - end");
    return names.get(index);
}

On executing our code, we’ll find the below messages printed in the console:

在执行我们的代码时,我们会发现控制台中打印出以下信息。

getRandomName() method - start
getRandomName() method - end

The variable name will hold “baeldung” at the end of the code execution.

变量name 将在代码执行结束时保持 “baeldung”

With it, we can easily infer that the parameter of orElse() is evaluated, even when having a non-empty Optional.

有了它,我们可以很容易地推断出orElse()的参数被评估了,即使有一个非空的Optional

3.2. orElseGet()

3.2. orElseGet()

Now let’s try writing similar code using orElseGet():

现在让我们试着用orElseGet()编写类似的代码。

String name = Optional.of("baeldung")
  .orElseGet(() -> getRandomName());

The above code won’t invoke the getRandomName() method.

上述代码不会调用getRandomName()方法。

Remember (from the Javadoc) that the Supplier method passed as an argument is only executed when an Optional value isn’t present.

记住(来自Javadoc),作为参数传递的Supplier方法只有在an Optional值不存在时才会执行。

Therefore, using orElseGet() for our case will save us the time involved in computing a random name.

因此,在我们的案例中使用orElseGet()将为我们节省计算随机name的时间。

4. Measuring Performance Impact

4.衡量绩效影响

Now, to also understand the differences in performance, let’s use JMH and see some actual numbers:

现在,为了同时了解性能的差异,让我们使用JMH,看看一些实际数字。

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseBenchmark() {
    return Optional.of("baeldung").orElse(getRandomName());
}

And orElseGet():

还有orElseGet()

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseGetBenchmark() {
    return Optional.of("baeldung").orElseGet(() -> getRandomName());
}

While executing our benchmark methods, we get:

在执行我们的基准方法时,我们得到。

Benchmark           Mode  Cnt      Score       Error  Units
orElseBenchmark     avgt   20  60934.425 ± 15115.599  ns/op
orElseGetBenchmark  avgt   20      3.798 ±     0.030  ns/op

As we can see, the performance impact might be substantial, even for such a simple use-case scenario.

正如我们所看到的,即使是这样一个简单的使用场景,其性能影响也可能是巨大的。

The numbers above might slightly vary; however, orElseGet() has clearly outperformed orElse() for our particular example.

上面的数字可能略有不同;但是,orElseGet()在我们的特定例子中,明显优于orElse()

After all, orElse() involves the computation of the getRandomName() method for each run.

毕竟,orElse() 涉及到每次运行的getRandomName() 方法的计算。

5. What’s Important?

5.什么是重要的?

Apart from the performance aspects, other factors worth considering include:

除了性能方面,其他值得考虑的因素包括。

  • What if the method would execute some additional logic? E.g. making some DB inserts or updates
  • Even when we assign an object to the orElse() parameter, we’re still creating “Other” object for no reason:
    String name = Optional.of("baeldung").orElse("Other")

That’s why it’s important for us to make a careful decision between orElse() and orElseGet() depending on our needs. By default, it makes more sense to use orElseGet() every time, unless the default object is already constructed and directly accessible.

这就是为什么我们要在orElse()orElseGet()之间根据我们的需求做出谨慎决定的原因。默认情况下,每次都使用orElseGet()更有意义,除非默认对象已经被构建并且可以直接访问。

6. Conclusion

6.结语

In this article, we learned the nuances between the Optional orElse() and OrElseGet() methods. We also discussed how such simple concepts can sometimes have a deeper meaning.

在这篇文章中,我们了解了Optional orElse() OrElseGet() 方法之间的细微差别。我们还讨论了这样简单的概念有时会有更深的含义。

As always, the complete source code can be found over on Github.

一如既往,完整的源代码可以在Github上找到over