我试图理解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。

还有其他的不同吗?


当前回答

考虑以下代码:

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:总是执行方法,如果Optional不为空也一样 orElseGet:只在Optional为空时执行它(+性能!)

请看这个例子(类OptionalExample):

public static void main(String[] args) {

    Optional<String> optionalNotEmpty = Optional.of("StringVal");
    
    // orElse: getDefaultValue called (useless)
    System.out.println(optionalNotEmpty.orElse(getDefaultValue()));
    
    // orElseGet: getDefaultValue not called (better solution)
    System.out.println(optionalNotEmpty.orElseGet(OptionalExample::getDefaultValue));
}

public static String getDefaultValue() {
    System.out.println("called");
    return "default value";
}

输出:

called
StringVal
StringVal

考虑以下代码:

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()中它将被调用

区别是相当微妙的,如果你不太注意,那么你就会以错误的方式使用它。

理解orElse()和orElseGet()之间区别的最好方法是,如果Optional<T>为空或不为空,orElse()将始终被执行,但orElseGet()只会在Optional<T>为空时被执行。

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

输出: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";
    }

输出:emptyOptional是NULL,我正在执行,它是正常的按 字典 对于orElseGet(),方法按照字典的含义执行 只有当Optional为时,orElseGet()部分才会执行 null。

基准:

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

备注:对于我们的特定示例,orElseGet()的性能明显优于orElse()。

希望它能消除像我这样想要最基本的例子的人的疑虑:)

简短的回答:

不管option . ispresent()值是多少,orElse()都会调用给定的函数 orElseGet()只会在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 (Redundant call)
    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 (Redundant call)");
        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");
    }
}