Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambda Chaining - Type Safety Enforcement

Snippet 1:

Optional.of(s).map(str -> str).orElse("");

Snippet 2:

Optional.of(s).map(str -> str).orElse(Optional.empty());

Snippet 3:

Optional.of(s).map(str -> Optional.of(str)).orElse("hello");

Snippet 1 is compiling fine but Snippet 2 & Snippet 3 compile with type incompatibility errors. While it's good that Snippet 2 & Snippet 3 fail, I do not understand how they are evaluated. In other words, I think I am missing some basics in terms of how the lambdas themselves are chained/invoked. Would appreciate if someone could help.

like image 896
Karthick Avatar asked Dec 31 '18 19:12

Karthick


People also ask

How do I avoid multiple nulls in Java 8?

We can get rid of all those null checks by utilizing the Java 8 Optional type. The method map accepts a lambda expression of type Function and automatically wraps each function result into an Optional . That enables us to pipe multiple map operations in a row.

What is the type of lambda expression in Java 8?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.

Why do companies still use Java 8?

One of the key reasons why Java 8 is still so popular is that it is an LTS (or Long-Term Support) version. Unfortunately, not all versions of Java are LTS versions!

Which of the following is correct about Java 8 lambda expression?

Q 5 - Which of the following is correct about Java 8 lambda expression? A - Lambda expressions are used primarily to define inline implementation of a functional interface.


2 Answers

Snippet 1:

Optional.of(s).map(str -> str).orElse("");

Compiles because the default value provided to orElse is the same type as the value the Optional contains i.e. a String.

Snippet 2:

Optional.of(s).map(str -> str).orElse(Optional.empty());

does not compile because after map you have a Optional<String> but then you're providing a Optional<String> in the orElse whereas it should be a String.

Snippet 3:

Optional.of(s).map(str -> Optional.of(str)).orElse("hello");

does not compile because after map you have a Optional<Optional<String>> but you're passing a String in the orElse whereas it should be a Optional<String>.

To conclude orElse is declared as:

public T orElse(T other)

and documented as:

Returns the value if present, otherwise return other.

i.e. orElse basically says "give me the value the optional contains if present otherwise take the default value" as well as that T must be the same type as the value the Optional contains.

so if you have a Optional<String then you must supply a String to orElse, if you have a Optional<Integer then you must supply a Integer to orElse etc...


On another note, the map function in your first and second example snippets are superfluous and you can, therefore, omit it completely.

Whenever you see your self calling Optional#map with the function as v -> v it's probably not needed.

like image 154
Ousmane D. Avatar answered Oct 28 '22 04:10

Ousmane D.


Breaking down Snippet 2:

Optional.of(s)            //Optional<String>
        .map(str -> str)  //Optional<String>
        .orElse(Optional.empty()); //String or Optional<String>?

And Snippet 3:

Optional.of(s)                        //Optional<String>
        .map(str -> Optional.of(str)) //Optional<Optional<String>>
        .orElse("hello");             //Optional<String> or String? 

Now, for Snippet 3, using flatMap can be used to get rid of the nested optionals:

Optional.of(s)                            //Optional<String>
        .flatMap(str -> Optional.of(str)) //Optional<String>
        .orElse("hello");                 //String
like image 31
Joe C Avatar answered Oct 28 '22 05:10

Joe C