简体   繁体   中英

What is intended behavior of Guava's Optional.or()?

A method where I chain optionals does not behave how I thought it would from reading the docs.

Assume all function_n return an Optional<Foo>

public Foo getFooFromService() {
     return this.function_1()
         .or(this.function_2())
         .or(this.function_3())
         .or(DEFAULT_VAL)

I thought that for the above code, if function_1 returned a non-absent Optional, then the program would return the inner value of it (the result of .get()) and not do any further computation on function_2 and function_3

My program is for sure doing that additional computation

In order to return a value from getFooFromService , function_1 and three or s have to be executed, meaning that their parameters will be evaluated. function_2 and function_3 will be run under any circumstances.

The option that might be suitable for you is the overloaded version that takes a Supplier which implies lazy evaluation.

public abstract T or(Supplier<? extends T> supplier)

UPDATE

It's a @Beta method (a subject to change), and I find it entirely useless. It resolves a Supplier<? extend T> Supplier<? extend T> to T , thus ruins the opportunity of building a chain. Basically, you can't rewrite your snippet to use this method.

UPDATE 1

But you could switch to Java's Optional and write

return function_1()
       .orElseGet(() -> function_2()
                        .orElseGet(() -> function_3()
                                         .orElse(DEFAULT_VAL)));

which isn't that expressive, but working as expected.

My formatting is awful, but you get the idea ;)

Guava "gently recommends" to use Java's Optional

So use Java's Optional to write the rather legible code:

import java.util.*;
class Main {
  public static void main(String[] args) {
    new Main().getFooFromService();
  }
  String getFooFromService() {
    return this.function_1()
      .or(this::function_2) // Requires Java 9
      .or(this::function_3) // Requires Java 9
      .orElse("DEFAULT_VALUE");
  }

  Optional<String> function_1() {
    System.out.println("function_1 called");
    return Optional.empty();
  }

  Optional<String> function_2() {
    System.out.println("function_2 called");
    return Optional.of("b");
  }

  Optional<String> function_3() {
    System.out.println("function_3 called");
    return Optional.of("c");
  }
}

You'll see that in this case, with the given setup, function_1 and function_2 are called, but not function_3 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM