Java `Optional.orElse()` 和 `Optional.orElseGet()` 之间的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33170109/
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
Difference between `Optional.orElse()` and `Optional.orElseGet()`
提问by jbx
I am trying to understand the difference between the Optional<T>.orElse()
and Optional<T>.orElseGet()
methods.
我试图了解Optional<T>.orElse()
和Optional<T>.orElseGet()
方法之间的区别。
The description for the orElse()
method is "Return the value if present, otherwise return other."
该orElse()
方法的描述是“如果存在则返回值,否则返回其他值”。
While, the description for the orElseGet()
method is "Return the value if present, otherwise invoke other and return the result of that invocation."
而该orElseGet()
方法的描述是“如果存在则返回值,否则调用其他并返回该调用的结果”。
The orElseGet()
method takes a Supplier functional interface, which essentially does not take any parameters and returns T
.
该orElseGet()
方法采用 Supplier 功能接口,该接口本质上不采用任何参数并返回T
。
In which situation would you need to use orElseGet()
? If you have a method T myDefault()
why wouldn't you just do optional.orElse(myDefault())
rather than optional.orElseGet(() -> myDefault())
?
在什么情况下需要使用orElseGet()
?如果你有一个方法,你T myDefault()
为什么不做optional.orElse(myDefault())
而不是optional.orElseGet(() -> myDefault())
?
It does not seem that orElseGet()
is postponing the execution of the lambda expression to some later time or something, so what's the point of it? (I would have thought that it would be more useful if it returned a safer Optional<T>
whose get()
never throws a NoSuchElementException
and isPresent()
always returns true... but evidently its not, it just returns T
like orElse()
).
这似乎不是orElseGet()
将 lambda 表达式的执行推迟到稍后的时间或其他什么,那有什么意义呢?(我会认为如果它返回一个更安全的,Optional<T>
它get()
从不抛出 aNoSuchElementException
并且isPresent()
总是返回 true会更有用......但显然它不是,它只是返回T
像orElse()
)。
Is there some other difference I am missing?
我还缺少其他一些区别吗?
采纳答案by biziclop
Take these two scenarios:
以这两个场景为例:
Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );
If opt
doesn't contain a value, the two are indeed equivalent. But if opt
doescontain a value, how many Foo
objects will be created?
如果opt
不包含值,则两者确实等效。但是如果opt
确实包含一个值,Foo
将创建多少个对象?
P.s.: of course in this example the difference probably wouldn't be measurable, but if you have to obtain your default value from a remote web service for example, or from a database, it suddenly becomes very important.
Ps:当然在这个例子中,差异可能无法衡量,但是如果您必须从例如远程 Web 服务或数据库中获取默认值,它突然变得非常重要。
回答by Jin Kwon
I reached here for the problem Kudomentioned.
我到达这里是为了解决工藤提到的问题。
I'm sharing my experience for others.
我正在为其他人分享我的经验。
orElse
, or orElseGet
, that is the question:
orElse
, 或者orElseGet
, 这就是问题:
static String B() {
System.out.println("B()...");
return "B";
}
public static void main(final String... args) {
System.out.println(Optional.of("A").orElse(B()));
System.out.println(Optional.of("A").orElseGet(() -> B()));
}
prints
印刷
B()...
A
A
orElse
evaluates the value of B() interdependently of the value of the optional. Thus, orElseGet
is lazy.
orElse
评估 B() 的值与可选的值相互依赖。因此,orElseGet
是懒惰的。
回答by devang
I would say the biggest difference between orElse
and orElseGet
comes when we want to evaluate something to get the new value in the else
condition.
我会说orElse
和之间的最大区别orElseGet
是当我们想要评估某些东西以获得else
条件中的新值时。
Consider this simple example -
考虑这个简单的例子——
// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
value = oldValue;
} else {
value = apicall().value;
}
Now let's transform the above example to using Optional
along with orElse
,
现在让我们将上面的示例转换为使用Optional
with orElse
,
// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);
Now let's transform the above example to using Optional
along with orElseGet
,
现在让我们将上面的示例转换为使用Optional
with orElseGet
,
// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);
When orElse
is invoked, the apicall().value
is evaluated and passed to the method. Whereas, in the case of orElseGet
the evaluation only happens if the oldValue
is empty. orElseGet
allows lazy evaluation.
当orElse
被调用时,apicall().value
被评估并传递给方法。而在orElseGet
评估的情况下,仅当oldValue
为空时才会发生。orElseGet
允许懒惰的评估。
回答by nxhoaf
Short Answer:
简答:
- orElse()will always call the given function whether you want it or not, regardless of
Optional.isPresent()
value - orElseGet()will only call the given function when the
Optional.isPresent() == false
- orElse()将始终调用给定的函数,无论您是否需要,无论
Optional.isPresent()
值如何 - orElseGet()只会在
Optional.isPresent() == false
In real code, 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())
For more details, consider the following example with this function:
有关更多详细信息,请考虑使用此函数的以下示例:
public Optional<String> findMyPhone(int phoneId)
The difference is as below:
区别如下:
X : buyNewExpensivePhone() called
+——————————————————————————————————————————————————————————————————+——————————————+
| Optional.isPresent() | true | false |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+——————————————————————————————————————————————————————————————————+——————————————+
When optional.isPresent() == false
, there is no difference between two ways. However, when optional.isPresent() == true
, orElse()
always calls the subsequent function whether you want it or not.
当 时optional.isPresent() == false
,两种方式没有区别。然而,当optional.isPresent() == true
,orElse()
总是叫你是否希望与否的后续功能。
Finally, test case used is as below:
最后,使用的测试用例如下:
Result:
结果:
------------- Scenario 1 - orElse() --------------------
1.1. Optional.isPresent() == true
Going to a very far store to buy a new expensive phone
Used phone: MyCheapPhone
1.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
------------- Scenario 2 - orElseGet() --------------------
2.1. Optional.isPresent() == true
Used phone: MyCheapPhone
2.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
Code:
代码:
public class TestOptional {
public Optional<String> findMyPhone(int phoneId) {
return phoneId == 10
? Optional.of("MyCheapPhone")
: Optional.empty();
}
public String buyNewExpensivePhone() {
System.out.println("\tGoing to a very far store to buy a new expensive phone");
return "NewExpensivePhone";
}
public static void main(String[] args) {
TestOptional test = new TestOptional();
String phone;
System.out.println("------------- Scenario 1 - orElse() --------------------");
System.out.println(" 1.1. Optional.isPresent() == true");
phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 1.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println("------------- Scenario 2 - orElseGet() --------------------");
System.out.println(" 2.1. Optional.isPresent() == true");
// Can be written as test::buyNewExpensivePhone
phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 2.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
}
}
回答by ratzip
Considering the following code:
考虑以下代码:
import java.util.Optional;
// one class needs to have a main() method
public class Test
{
public String orelesMethod() {
System.out.println("in the Method");
return "hello";
}
public void test() {
String value;
value = Optional.<String>ofNullable("test").orElseGet(this::orelesMethod);
System.out.println(value);
value = Optional.<String>ofNullable("test").orElse(orelesMethod());
System.out.println(value);
}
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
Test test = new Test();
test.test();
}
}
if we get value
in this way: Optional.<String>ofNullable(null)
, there is no difference between orElseGet() and orElse(), but if we get value
in this way: Optional.<String>ofNullable("test")
, orelesMethod()
in orElseGet()
will not be called but in orElse()
it will be called
如果我们value
以这样的方式Optional.<String>ofNullable(null)
,有orElseGet()和否则容易()没有什么区别,但如果我们value
以这样的方式Optional.<String>ofNullable("test")
,orelesMethod()
在orElseGet()
不会被调用,但orElse()
它会被称为
回答by Maroun
The following example should demonstrate the difference:
下面的例子应该展示了不同之处:
String destroyTheWorld() {
// destroy the world logic
return "successfully destroyed the world";
}
Optional<String> opt = Optional.empty();
// we're dead
opt.orElse(destroyTheWorld());
// we're safe
opt.orElseGet(() -> destroyTheWorld());
The answer appears in the docs as well.
答案也出现在文档中。
public T orElseGet(Supplier<? extends T> other)
:
public T orElseGet(Supplier<? extends T> other)
:
Return the value if present, otherwise invokeother and return the result of that invocation.
返回值(如果存在),否则调用other 并返回该调用的结果。
The Supplier
won'tbe invoked if the Optional
presents. whereas,
如果存在,Supplier
则不会调用Optional
。然而,
Return the value if present, otherwise return other.
如果存在则返回值,否则返回其他值。
If other
is a method that returns a string, it will be invoked, but it's value won't be returned in case the Optional
exists.
如果other
是一个返回字符串的方法,它将被调用,但如果Optional
存在,则不会返回它的值。
回答by Vishwa Ratna
The difference is pretty subtle and if you dont pay much attention then you will keep it using in a wrong way.
差异非常微妙,如果您不注意,那么您将继续以错误的方式使用它。
Best way to understand the difference between orElse()
and orElseGet()
is that orElse()
will always be executed if the Optional<T>
is nullor not, But orElseGet()
will only be executed when Optional<T>
is null.
最好的方式来理解之间的区别orElse()
,并orElseGet()
是,orElse()
如果总是被执行Optional<T>
为空或不是,但orElseGet()
何时才会执行Optional<T>
为空。
The dictionary meaning of orElseis :-execute the part when something is not present, but here it contradicts, see the below example:
orElse的字典含义是:-当某物不存在时执行该部分,但在这里它是矛盾的,见下面的例子:
Optional<String> nonEmptyOptional = Optional.of("Vishwa Ratna");
String value = nonEmptyOptional.orElse(iAmStillExecuted());
public static String iAmStillExecuted(){
System.out.println("nonEmptyOptional is not NULL,still I am being executed");
return "I got executed";
}
Output:nonEmptyOptional is not NULL,still I am being executed
输出:nonEmptyOptional 不是 NULL,我仍然被执行
Optional<String> emptyOptional = Optional.ofNullable(null);
String value = emptyOptional.orElse(iAmStillExecuted());
public static String iAmStillExecuted(){
System.out.println("emptyOptional is NULL, I am being executed, it is normal as
per dictionary");
return "I got executed";
}
Output: emptyOptional is NULL, I am being executed, it is normal as per dictionary
For
orElseGet()
, The method goes as per dictionary meaning, TheorElseGet()
part will be executed only when the Optional is null.
输出:emptyOptional 为NULL,我正在被执行,按照字典是正常的
对于
orElseGet()
,该方法按照字典的含义进行,该orElseGet()
部分仅在 Optional 为null时才会执行 。
Benchmarks:
基准:
+--------------------+------+-----+------------+-------------+-------+
| Benchmark | Mode | Cnt | Score | Error | Units |
+--------------------+------+-----+------------+-------------+-------+
| orElseBenchmark | avgt | 20 | 60934.425 | ± 15115.599 | ns/op |
+--------------------+------+-----+------------+-------------+-------+
| orElseGetBenchmark | avgt | 20 | 3.798 | ± 0.030 | ns/op |
+--------------------+------+-----+------------+-------------+-------+
Remarks:
orElseGet()
has clearly outperformedorElse()
for our particular example.
备注: 对于我们的特定示例,
orElseGet()
明显优于orElse()
其他示例。
Hope it clears the doubts of people like me who wants the very basic ground example :)
希望它能消除像我这样想要非常基本的地面示例的人的疑虑:)
回答by Piyush N
First of all check the declaration of both the methods.
首先检查两个方法的声明。
1) OrElse:Execute logic and pass result as argument.
1) OrElse:执行逻辑并将结果作为参数传递。
public T orElse(T other) {
return value != null ? value : other;
}
2) OrElseGet:Execute logic if value inside the optional is null
2) OrElseGet:如果可选中的值为空则执行逻辑
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
Some explanation on above declaration:The argument of “Optional.orElse” always gets executed irrespective of the value of the object in optional (null, empty or with value). Always consider the above-mentioned point in mind while using “Optional.orElse”, otherwise use of “Optional.orElse” can be very risky in the following situation.
关于上述声明的一些解释:“Optional.orElse”的参数总是被执行,而不管可选对象的值(空、空或带值)。使用“Optional.orElse”时请始终牢记上述要点,否则在以下情况下使用“Optional.orElse”可能会非常危险。
Risk-1) Logging Issue:If content inside orElse contains any log statement: In this case, you will end up logging it every time.
风险-1) 日志问题:如果 orElse 中的内容包含任何日志语句:在这种情况下,您最终将每次都记录它。
Optional.of(getModel())
.map(x -> {
//some logic
})
.orElse(getDefaultAndLogError());
getDefaultAndLogError() {
log.error("No Data found, Returning default");
return defaultValue;
}
Risk-2) Performance Issue:If content inside orElse is time-intensive: Time intensive content can be any i/o operations DB call, API call, file reading. If we put such content in orElse(), the system will end up executing a code of no use.
风险-2) 性能问题:如果 orElse 中的内容是时间密集型的:时间密集型内容可以是任何 I/O 操作 DB 调用、API 调用、文件读取。如果我们将这些内容放入 orElse() 中,系统最终将执行无用的代码。
Optional.of(getModel())
.map(x -> //some logic)
.orElse(getDefaultFromDb());
getDefaultFromDb() {
return dataBaseServe.getDefaultValue(); //api call, db call.
}
Risk-3) Illegal State or Bug Issue:If content inside orElse is mutating some object state: We might be using the same object at another place let say inside Optional.map function and it can put us in a critical bug.
风险-3) 非法状态或错误问题:如果 orElse 中的内容正在改变某个对象状态:我们可能在另一个地方使用相同的对象,比如在 Optional.map 函数中,它可以把我们置于一个严重的错误中。
List<Model> list = new ArrayList<>();
Optional.of(getModel())
.map(x -> {
})
.orElse(get(list));
get(List < String > list) {
log.error("No Data found, Returning default");
list.add(defaultValue);
return defaultValue;
}
Then, When can we go with orElse()?Prefer using orElse when the default value is some constant object, enum. In all above cases we can go with Optional.orElseGet() (which only executes when Optional contains non empty value)instead of Optional.orElse(). Why?? In orElse, we pass default result value, but in orElseGet we pass Supplier and method of Supplier only executes if the value in Optional is null.
那么,我们什么时候可以使用 orElse() 呢?当默认值是某个常量对象 enum 时,最好使用 orElse。在上述所有情况下,我们可以使用 Optional.orElseGet()(仅在 Optional 包含非空值时执行)而不是 Optional.orElse()。为什么??在 orElse 中,我们传递默认结果值,但在 orElseGet 中,我们传递 Supplier 并且 Supplier 的方法仅在 Optional 中的值为 null 时才执行。
Key takeaways from this:
关键要点:
- Do not use “Optional.orElse” if it contains any log statement.
- Do not use “Optional.orElse” if it contains time-intensive logic.
- Do not use “Optional.orElse” if it is mutating some object state.
- Use “Optional.orElse” if we have to return a constant, enum.
- Prefer “Optional.orElseGet” in the situations mentioned in 1,2 and 3rd points.
- 如果“Optional.orElse”包含任何日志语句,请不要使用。
- 如果“Optional.orElse”包含时间密集型逻辑,请不要使用。
- 如果“Optional.orElse”正在改变某些对象状态,请不要使用它。
- 如果我们必须返回一个常量枚举,请使用“Optional.orElse”。
- 在第 1,2 和第 3 点中提到的情况下,更喜欢“Optional.orElseGet”。
I have explained this in point-2 (“Optional.map/Optional.orElse” != “if/else”) my medium blog. Use Java8 as a programmer not as a coder
我已经在第 2 点(“Optional.map/Optional.orElse”!=“if/else”)我的媒体博客中解释了这一点。使用 Java8 作为程序员而不是编码员