Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unfolding multiple Optional variables in Java 8

Tags:

I have the following problem. Let's say you have 2 Optional variables

Optional<Contact> c1 = ...
Optional<Contact> c2 = ...

and a method which needs 2 variables of type Contact

void match(Contact c1, Contact c2) {...}

and you need to unwrap both c1 and c2 Optional vars and pass them into the match() method.

My question is "Which is the most elegant way to do that in Java 8?"

So far I've found 2 ways:

  1. by using isPresent

    if (c1.isPresent() && c2.isPresent()) {
        match(c1.get(), c2.get());
    }
    
  2. by using nested ifPresent

    c1.ifPresent((Contact _c1) -> {
        c2.ifPresent((Contact _c2) -> {
            match(_c1, _c2);
        });
    });
    

Both ways are terrible in my opinion. In Scala I can do this:

for {
    contact1 <- c1
    contact2 <- c2
} yield {
    match(contact1, contact2);
}

is there a way in Java 8 to do it neater than I outlined above?

like image 820
Nico Avatar asked Apr 06 '16 10:04

Nico


People also ask

How do you pass optional parameters in Java 8?

Use the Optional Container Object to Have Optional Parameters in Java. In Java, Optional is a container object that may or may not contain a non-null value. If a value is present, then the isPresent() method will return true, and the get() method will return the value.

Why does Java 8 have optionals?

So, to overcome this, Java 8 has introduced a new class Optional in java. util package. It can help in writing a neat code without using too many null checks. By using Optional, we can specify alternate values to return or alternate code to run.

Can we pass optional parameters in Java?

There are no optional parameters in Java. What you can do is overloading the functions and then passing default values.


2 Answers

Solution you provided in scala is just syntax sugar for using flatMaps internally. You can use flatmaps in Java 8 too (but there are no syntax sugar for it).

c1.flatMap(contact1 -> c2.flatMap(contact2 -> match(contact1, contact2)));

it is almost the same thing as solution 2 you provided. You also can use applicative functor from https://github.com/aol/cyclops-react (I'm one of contributors) or any other functional java 8 library.

Applicative functor

Optional<String> o3 = Maybe.fromOptional(o1).ap2(String::concat).ap(o2).toOptional();

For-comprehension

Do.add(o1)
    .add(o2)
    .yield(a->b->a.concat(b));
like image 73
Nikita Sapozhnikov Avatar answered Oct 09 '22 05:10

Nikita Sapozhnikov


You could desugar the Scala for-comprehension to map/flatMap in Java 8 with a function like:

public static <T,K,V> Optional<V> map2(Optional<T> opt1, Optional<K> opt2, BiFunction<T, K, V> f) {
    Optional<V> result = opt1.flatMap(t1 -> opt2.map(t2 -> f.apply(t1, t2)));
    return result;
}

And then pass your function match

like image 45
Jose Antonio Jimenez Saez Avatar answered Oct 09 '22 06:10

Jose Antonio Jimenez Saez