Java 当我需要在 Optional.orElse() 上使用 Optional.orElseGet() 时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44261253/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When I need to use Optional.orElseGet() over Optional.orElse()
提问by TVK
采纳答案by Ole V.V.
I think I am starting to understand your question. Execution order with Optional
can be different from what we are used to in procedural programming (the same is true for Java streams and other code using lambdas).
我想我开始理解你的问题了。执行顺序可能与Optional
我们在过程编程中习惯的不同(Java 流和其他使用 lambda 的代码也是如此)。
I will use the two examples from Eugene's answer:
我将使用尤金回答中的两个例子:
o1.orElse(new MyObject()); // 1055e4af
This is plain old Java: it's a call to orElse()
taking new MyObject()
as argument. So the argument is evaluated first and a new MyObject
created. This is then passed to orElse()
. orElse()
looks to see whether a value is present in the Optional
; if so it returns that value (discarding the newly created object); if not, it returns the object given to it in the argument. This was the simpler example.
这是普通的旧 Java:它是一个orElse()
将new MyObject()
作为参数的调用。所以参数首先被评估并MyObject
创建一个新的。然后将其传递给orElse()
. orElse()
查看 中是否存在值Optional
;如果是,则返回该值(丢弃新创建的对象);如果不是,则返回参数中提供给它的对象。这是更简单的例子。
o1.orElseGet(() -> {
System.out.println("Should I see this");
return new MyObject();
});
Again we have a method call with one argument, and again the argument is evaluated first. The lambda is only created and passed as a supplier. The code inside { }
is not executed yet (you also see no Should I see this
in Eugene's output). Again orElseGet
looks to see if there is a value present in the Optional
. If there is, the value is returned and the supplier we passed is ignored. If there isn't, the supplier is invoked, the code inside { }
is executed to get the value to be returned from orElseGet()
.
同样,我们有一个带有一个参数的方法调用,并且再次首先评估该参数。lambda 仅作为供应商创建和传递。里面的代码{ }
还没有执行(你Should I see this
在 Eugene 的输出中也没有看到)。再次orElseGet
查看Optional
. 如果存在,则返回该值并忽略我们传递的供应商。如果没有,则调用供应商,{ }
执行内部代码以获取要从 返回的值orElseGet()
。
In the first case, one may say that a MyObject
is created and wasted. In the second a Supplier
is created and wasted. What you get in return is terse and null-pointer safe code in both cases. So very often it's not important which one you pick. If creating the MyObject
is costly or has unwanted side effects, you will of course want the second version where the object is only created when it is asked for, and is never wasted. Eugene in a comment mentions the case where the returned object comes from a database call. Database calls are usually time-consuming enough that you don't want to make one for no purpose.
在第一种情况下,可以说 aMyObject
被创建和浪费了。在第二个 aSupplier
被创建和浪费。在这两种情况下,您得到的回报都是简洁和空指针安全的代码。所以很多时候你选择哪一个并不重要。如果创建MyObject
成本高昂或有不需要的副作用,您当然会想要第二个版本,其中对象仅在需要时创建,并且永远不会浪费。Eugene 在评论中提到了返回对象来自数据库调用的情况。数据库调用通常非常耗时,您不想无缘无故地调用。
回答by Eugene
How about an example:
举个例子:
static class MyObject {
public MyObject() {
System.out.println("Creating one..." + this);
}
}
And some usage:
还有一些用法:
Optional<MyObject> o1 = Optional.of(new MyObject()); // 7382f612
o1.orElse(new MyObject()); // 1055e4af
o1.orElseGet(() -> {
System.out.println("Should I see this");
return new MyObject();
});
And some output:
还有一些输出:
Creating one... MyObject@7382f612
Creating one... MyObject@1055e4af
In case Optional
has a value; orElse
is still called but not used. On the contradictory orElseGet
is not called.
如果Optional
有一个值;orElse
仍被调用但未使用。就矛盾orElseGet
不叫。
Consider the case when creating the object is expensive; which one you will use?
考虑创建对象代价高昂的情况;你会使用哪一种?
It's actually easier to understand I think if you look in the code:
如果您查看代码,我认为实际上更容易理解:
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
回答by nxhoaf
As answered here, you might want to consider the second approach when the required resource is expensive to get.
正如此处所回答的,当所需资源的获取成本很高时,您可能需要考虑第二种方法。
// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())