Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Mapping multiple optional parameters into a function

Let's say that I have function Object f(String a, String b) and I want to call two different functions that return Optional Strings to get the parameters for f Optional<String> getA() and Optional<String> getB(). I can think of two solutions but neither look all that clean, especially when you have even more parameters:

1:

return getA().flatMap(
    a -> getB().map(
        b -> f(a,b)).get()

2:

Optional<String> a = getA();
Optional<String> b = getB();
if(a.isPresent() && b.isPresent()) {
    return f(a.get(), b.get());
}

Is there a cleaner way to do this?

like image 552
Lezorte Avatar asked Mar 05 '19 16:03

Lezorte


People also ask

Can a method have 2 optional parameters?

Can a method have 2 optional parameters? If you want to define multiple optional parameters, then the method declaration must be as shown below. The defined GetDetails() method can be accessed as shown below. GetDetails(1); GetDetails(1, “Rohini”);

How do you pass optional parameters to a method?

By Params Keyword: You can implement optional parameters by using the params keyword. It allows you to pass any variable number of parameters to a method. But you can use the params keyword for only one parameter and that parameter is the last parameter of the method.

Can we pass optional parameters in Java?

Unlike some languages such as Kotlin and Python, Java doesn't provide built-in support for optional parameter values. Callers of a method must supply all of the variables defined in the method declaration.


1 Answers

You've just stumbled upon a concept called lifting in functional programming, that enables you to lift regular functions (e.g. A -> B) into new domains (e.g. Optional<A> -> Optional<B>).

There's also a syntactic sugar for flatMapping and mapping more comfortably called the do notation in Haskell and similar languages, and for comprehension in Scala. It gives you a way to keep the flow linear and avoid nesting (that you were forced to go through in your example 1).

Java, unfortunately has nothing of the sort, as its functional programming capabilities are meager, and even Optional isn't really a first-class citizen (no standard API actually uses it). So you're stuck with the approaches you've already discovered.

In case you're curious about the concepts mentioned above, read on.

Lifting

Assuming you have:

public String f(A a, B b) {
    return b + "-" + a;
}

With its Scala equivalent:

def f(a: A, b: B) = b + "-" + a

Lifting f into Option (same as Optional in Java) would look like this (using Scalaz library, see here for Cats)

val lifted = Monad[Option].lift2(f)

lifted is now a function equivalent to:

public Optional<String> f(Optional<A> a, Optional<B> b) {
    if(a.isPresent() && b.isPresent()) {
        return Optional.of(b + "-" + a);
    }
    return  Optional.empty;
}

Exactly what you're looking for, in 1 line, and works for any context (e.g. List, not just Option) and any function.

For comprehension / Do notation

Using for comprehension, your example would look like this (I think, my Scala is weak):

for { 
    a <- getA();
    b <- getB();
} yield f(a, b)

And again, this is applicable to anything that can be flatMapped over, like List, Future etc.

like image 166
kaqqao Avatar answered Sep 22 '22 12:09

kaqqao