我试图理解Optional<T>. orelse()和Optional<T>. orelseget()方法之间的区别。

orElse()方法的描述是“如果存在则返回值,否则返回other”。

而orElseGet()方法的描述是“如果存在则返回值,否则调用other并返回该调用的结果。”

orElseGet()方法接受一个Supplier函数接口,该接口本质上不接受任何参数并返回T。

在哪种情况下需要使用orElseGet()?如果你有一个方法T myDefault()你为什么不只是做option . orelse (myDefault())而不是option . orelseget (() -> myDefault()) ?

似乎orElseGet()并没有将lambda表达式的执行推迟到以后的某个时间或其他时间,那么它的意义是什么呢?(我认为它会更有用,如果它返回一个更安全的Optional<T>,其get()从不抛出NoSuchElementException, isPresent()总是返回true…但显然不是,它只是像orElse()一样返回T。

还有其他的不同吗?


当前回答

我来到这里是为了工藤提到的问题。

我在和别人分享我的经验。

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()) // B()'s gonna be invoked anyway
    );

    System.out.println("----");

    System.out.println(
        Optional.of("A").orElseGet(() -> B()) // B() won't be invoked
    );
}

打印

B()...
A
----
A

orElse计算B()的值与optional的值相互依赖。因此,orElseGet是懒惰的。

其他回答

首先,检查两个方法的声明。

1) OrElse:执行逻辑并将结果作为参数传递。

public T orElse(T other) {    
 return value != null ? value : other;
}

2) OrElseGet:如果optional中的value为空,则执行逻辑

public T orElseGet(Supplier<? extends T> other) {
  return value != null ? value : other.get(); 
}

关于上述声明的解释: 可选的参数。orElse "总是被执行,而不管可选对象的值(null, empty或with value)。在使用“可选”时,一定要考虑到上述几点。orElse”,否则使用“Optional”。“orElse”在以下情况下可能非常危险。

风险-1)日志问题:如果orElse内部的内容包含任何日志语句: 在这种情况下,您将每次都记录它。

Optional.of(getModel())
   .map(x -> {
      //some logic
   })
  .orElse(getDefaultAndLogError());
 
getDefaultAndLogError() {
  log.error("No Data found, Returning default");
  return defaultValue;
}

风险-2)性能问题:如果orElse中的内容是时间密集型的: 时间密集型内容可以是任何i/o操作DB调用,API调用,文件读取。如果将这些内容放在orElse()中,系统最终将执行无用的代码。

Optional.of(getModel())
   .map(x -> //some logic)
   .orElse(getDefaultFromDb());

getDefaultFromDb() {
   return dataBaseServe.getDefaultValue(); //api call, db call.
}

风险-3)非法状态或Bug问题:如果orElse内部的内容正在改变某些对象状态: 我们可能会在另一个地方使用相同的对象,比如在Optional内部。地图功能,它会让我们陷入一个严重的错误。

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;
}

那么,我们什么时候可以用orElse()? 当默认值是某个常量对象时,首选使用orElse。在上述所有情况下,我们都可以使用option . orelseget()(仅在Optional包含空值时执行)而不是option . orelse()。为什么? ?在orElse中,我们传递默认的结果值,但在orElseGet中,我们传递Supplier和Supplier的方法,只有当Optional中的值为空时才执行。

这里的关键要点是:

不要使用“可选”。orElse”,如果它包含任何日志语句。 不要使用“可选”。orElse”,如果它包含时间密集型逻辑。 不要使用“可选”。如果它正在改变某个对象状态,则使用orElse。 使用“可选的。orElse”如果我们必须返回一个常量,enum。 更喜欢“可选的。orElseGet”在1、2和3点提到的情况下。

我在第2点(“Optional.map/Optional。orElse " != " if/else ")我的媒体博客。作为程序员使用Java8,而不是作为编码器

考虑以下代码:

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"), orElseGet()中的orelesMethod()将不会被调用,但在orElse()中它将被调用

以以下两种情况为例:

Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );

如果opt不包含值,则两者确实是等效的。但是如果opt包含一个值,将创建多少个Foo对象?

附注:当然,在这个例子中,差异可能无法测量,但如果您必须从远程web服务或数据库获取默认值,那么它就变得非常重要了。

我来到这里是为了工藤提到的问题。

我在和别人分享我的经验。

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()) // B()'s gonna be invoked anyway
    );

    System.out.println("----");

    System.out.println(
        Optional.of("A").orElseGet(() -> B()) // B() won't be invoked
    );
}

打印

B()...
A
----
A

orElse计算B()的值与optional的值相互依赖。因此,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()。值被计算并传递给方法。然而,在orElseGet的情况下,只有当oldValue为空时才会计算。orElseGet允许惰性求值。