bdev03
bdev03

Reputation: 425

Google Guava Optional - How to short circuit multiple chained expressions

Suppose I have multiple methods that each return Optional. I want to chain them together so that if one of them returns an Optional with a value then the chain should stop propagation and should stop at that point. e.g. Let's say that f1, f2, f3 each return Optional.

If I do something like this,

Optional<T> result = f1.or(f2).or(f3);

I see that even if f2 returns an Optional.of(t), f3 still gets called.

I want it to behave like a short circuiting expression but it does not work that way.

Can anyone please help me with this.

Upvotes: 4

Views: 580

Answers (2)

Frank Pavageau
Frank Pavageau

Reputation: 11715

You'd need to use a Supplier to make it lazy:

Stream.<Supplier<Optional<T>>>of(this::f1, this::f2, this::f3)
        .map(Supplier::get)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .findFirst();

Example, in the same vein as Mike's answer:

public class LazyOptional {
    public static void main(String... args) {
        new LazyOptional().run();
    }

    public void run() {
        Stream.<Supplier<Optional<String>>>of(this::f1, this::f2, this::f3)
                .map(Supplier::get)
                .peek(System.out::println)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .findFirst();
    }

    public Optional<String> f1() {
        return Optional.empty();
    }

    public Optional<String> f2() {
        return Optional.of("a");
    }

    public Optional<String> f3() {
        return Optional.of("b");
    }
}

Output:

Optional.empty
Optional[a]

Upvotes: 1

mkobit
mkobit

Reputation: 47269

You can accomplish this by using a short circuiting stream in Java 8. You can apply a mapping to the result to make the result also come out as an Optional<T>, rather than an Optional<Optional<T>>.

Optional<Integer> e1 = Optional.empty();
Optional<Integer> e2 = Optional.empty();
Optional<Integer> p = Optional.of(1337);
Optional<Integer> e3 = Optional.empty();
Optional<Integer> e4 = Optional.empty();

// peek used to show output
Optional<Integer> first = Stream.of(e1, e2, p, e3, e4)
    .peek(System.out::println)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

Output:

Optional.empty
Optional.empty
Optional[1337]

Upvotes: 0

Related Questions