Home > other >  Java: How to reduce Optionals of different types?
Java: How to reduce Optionals of different types?

Time:04-30

I know it's possible to merge Optionals of the same type.

public static void main(String[] args) {
    var foo = Stream.of(Optional.of("a"), Optional.of("b"))
        .flatMap(Optional::stream)
        .reduce((a, b) -> a   "-"   b)
        .orElse(null);
    System.out.println(foo); // prints "a-b"
}

However I'm struggling to merge Optionals of different types.

public class Example {

    record A(){}

    record B(){}

    record C(A a, B b){}

    public static void main(String[] args) {
        var foo = Stream.of(Optional.of(new A()), Optional.of(new B()))
            .flatMap(Optional::stream)
            .reduce((a, b) -> new C(a, b))
            .orElse(null);
        System.out.println(foo);
    }
    
}

That does not work and I'm getting the error.

Type mismatch: cannot convert from Example.C to capture#1-of ? extends Record

I tried different versions with type casting but no success so far. Any ideas?


Edit: adding some more information

This is obviously a trivial and very simple example. In real life I have two methods

  1. The first one returns an Optional of type User
  2. The second one returns an Optional of Type Animal

When both are successful / not empty I'd like to call a method myMethod(User user, Animal animal). So the question is basically about joining / merging two optionals and work with the enclosed values afterwards.

CodePudding user response:

If you have a fixed number of optionals, use a chain of flatMaps, ending with another flatMap or map, in order to map all of them to Optional<AnotherType>.

In the case of two optionals, this looks like:

Optional<A> aOpt = Optional.of(new A());
Optional<B> bOpt = Optional.of(new B());
Optional<C> c = aOpt.flatMap(a ->
                bOpt.map(b ->
                    new C(a, b)));

You can generalise this to n optionals:

// opt1 to opt5 can all be different types of optionals
opt1.flatMap(a ->
opt2.flatMap(b ->
opt3.flatMap(c ->
opt4.flatMap(d ->
opt5.map(e -> // if f returns another optional, you'd use flatMap here too
    f(a, b, c, d, e))))));
  • Related