我试图了解Optional<T>.orElse()
和Optional<T>.orElseGet()
方法之间的区别。
orElse()
方法的描述是“如果存在则返回值,否则返回其他值”。
虽然,orElseGet()
方法的描述是“如果存在则返回值,否则调用other并返回该调用的结果”。
orElseGet()
方法采用供应商功能接口,基本上不接受任何参数并返回T
。
在哪种情况下你需要使用orElseGet()
?如果你有一个方法T myDefault()
你为什么不只是做optional.orElse(myDefault())
而不是optional.orElseGet(() -> myDefault())
?
似乎orElseGet()
没有将lambda表达式的执行推迟到以后的某个时间或什么的,所以它有什么意义呢? (我本以为如果它返回一个更安全的Optional<T>
更有用,其get()
从不投掷NoSuchElementException
和isPresent()
总是返回真实......但显然它不是,它只是返回T
像orElse()
)。
我还缺少其他一些差异吗?
采取以下两种情况:
Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );
如果opt
不包含值,则两者确实等价。但是如果opt
确实包含一个值,那么将创建多少个Foo
对象?
P.s。:当然在本例中,差异可能无法衡量,但如果您必须从远程Web服务或数据库中获取默认值,则突然变得非常重要。
简答:
Optional.isPresent()
值如何,orElse()总是会调用给定的函数,无论你是否需要它Optional.isPresent() == false
时调用给定的函数在实际代码中,当需要的资源很昂贵时,您可能需要考虑第二种方法。
// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())
有关更多详细信息,请考虑以下使用此函数的示例:
public Optional<String> findMyPhone(int phoneId)
区别如下:
X : buyNewExpensivePhone() called
+——————————————————————————————————————————————————————————————————+——————————————+
| Optional.isPresent() | true | false |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+——————————————————————————————————————————————————————————————————+——————————————+
当optional.isPresent() == false
,两种方式之间没有区别。然而,当optional.isPresent() == true
,orElse()
总是调用后续函数,无论你是否想要它。
最后,使用的测试用例如下:
结果:
------------- 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
码:
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");
}
}
我到达这里是因为Kudo提到的问题。
我正在为别人分享我的经验。
orElse
, or orElseGet
, that is the question: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()));
}
版画
B()...
A
A
orElse
与可选项的值相互依赖地计算B()的值。因此,orElseGet
是懒惰的。
我想说orElse
和orElseGet
之间的最大区别在于我们想要评估一些东西来获得else
条件下的新值。
考虑这个简单的例子 -
// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
value = oldValue;
} else {
value = apicall().value;
}
现在让我们将上面的例子转换为使用Optional
和orElse
,
// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);
现在让我们将上面的例子转换为使用Optional
和orElseGet
,
// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);
当调用orElse
时,将评估apicall().value
并将其传递给该方法。然而,在orElseGet
的情况下,只有在oldValue
为空时才会进行评估。 orElseGet
允许懒惰评估。
以下示例应说明差异:
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());
答案也出现在文档中。
public T orElseGet(Supplier<? extends T> other)
:
返回值(如果存在),否则调用other并返回该调用的结果。
如果Supplier
出现,将不会援引Optional
。然而,
如果存在则返回值,否则返回其他值。
如果other
是一个返回字符串的方法,它将被调用,但是如果Optional
存在则不会返回它的值。
考虑以下代码:
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();
}
}
如果我们以这种方式获得value
:Optional.<String>ofNullable(null)
,orElseGet()和orElse()之间没有区别,但是如果我们以这种方式获得value
:Optional.<String>ofNullable("test")
中的orelesMethod()
,orElseGet()
将不被调用,但是在orElse()
中它将被调用