Reputation: 24472
What's the difference between these two methods: Optional.flatMap()
and Optional.map()
?
An example would be appreciated.
Upvotes: 251
Views: 178854
Reputation: 1528
Below is the illustration of map()
and flatMap()
functions, otherwise Optional
is primarily designed to be used as a return type only.
As you already may know Optional
is a kind of container which may or may not contain a single object, so it can be used wherever you anticipate a null
value (you may never see NPE if you use Optional
properly).
For example if you have a method which expects a Person
object which may be nullable you may want to write the method something like this:
void doSome(Optional<Person> person) {
/* and here you want to retrieve some property phone out of person
you may write something like this:
*/
Optional<String> phone = person.map((p) -> p.getPhone());
phone.ifPresent((ph) -> dial(ph));
}
class Person {
private String phone;
// setters, getters
}
Here you have returned a String
type which is automatically wrapped in an Optional
type.
If Person
class looked like this (i.e. phone
is also Optional
):
class Person {
private Optional<String> phone;
// setters, getters
}
In this case invoking map()
function will wrap the returned value in Optional
and yield something like:
Optional<Optional<String>>
But you may want Optional<String>
instead, so here comes flatMap()
:
void doSome(Optional<Person> person) {
Optional<String> phone = person.flatMap((p) -> p.getPhone());
phone.ifPresent((ph) -> dial(ph));
}
Never call get()
method (if you need to) on an Optional
without checking it with isPresent()
unless you can't live without NullPointerException
.
Upvotes: 12
Reputation: 18612
Optional.map()
:Takes every element and if the value exists, it is passed to the function:
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
Now added has one of three values: true
or false
wrapped into an Optional , if optionalValue
was present, or an empty Optional otherwise.
If you don't need to process the result you can simply use ifPresent()
, it doesn't have return value:
optionalValue.ifPresent(results::add);
Optional.flatMap()
:Works similar to the same method of streams. Flattens out the stream of streams. With the difference that if the value is presented it is applied to function. Otherwise, an empty optional is returned.
You can use it for composing optional value functions calls.
Suppose we have methods:
public static Optional<Double> inverse(Double x) {
return x == 0 ? Optional.empty() : Optional.of(1 / x);
}
public static Optional<Double> squareRoot(Double x) {
return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
}
Then you can compute the square root of the inverse, like:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
or, if you prefer:
Optional<Double> result = Optional.of(-4.0)
.flatMap(MyMath::inverse)
.flatMap(MyMath::squareRoot);
If either the inverse()
or the squareRoot()
returns Optional.empty()
, the result is empty.
Upvotes: 5
Reputation: 4655
They do the same thing.
The only difference is that, the lambda
return's type is wrapped by Optional
or not.
For normal usage, map
is shorter than flatMap
Example:
package bj;
import java.util.Optional;
import static java.lang.System.out;
public class App {
public static void main(String[] args) {
out.println(Optional.of(10).map (x -> x * x));
out.println(Optional.of(10).flatMap(x -> Optional.of(x * x)));
out.println(Optional.of(10).map (x -> Optional.of(x * x).get()));
out.println(Optional.<Integer>empty().map (x -> x * x));
out.println(Optional.<Integer>empty().flatMap(x -> Optional.of(x * x)));
out.println(Optional.<Integer>empty().map (x -> Optional.of(x * x).get()));
}
}
Output:
Optional[100]
Optional[100]
Optional[100]
Optional.empty
Optional.empty
Optional.empty
Upvotes: 1
Reputation: 359
You can refer below link to understand in detail (best explanation which I could find):
https://www.programmergirl.com/java-8-map-flatmap-difference/
Both map and flatMap - accept Function. The return type of map() is a single value whereas flatMap is returning stream of values
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
Upvotes: -1
Reputation: 191
Okay. You only need to use 'flatMap' when you're facing nested Optionals. Here's the example.
public class Person {
private Optional<Car> optionalCar;
public Optional<Car> getOptionalCar() {
return optionalCar;
}
}
public class Car {
private Optional<Insurance> optionalInsurance;
public Optional<Insurance> getOptionalInsurance() {
return optionalInsurance;
}
}
public class Insurance {
private String name;
public String getName() {
return name;
}
}
public class Test {
// map cannot deal with nested Optionals
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.map(Car::getOptionalInsurance) // ① leads to a Optional<Optional<Insurance>
.map(Insurance::getName); // ②
}
}
Like Stream, Optional#map will return a value wrapped by a Optional. That's why we get a nested Optional -- Optional<Optional<Insurance>
. And at ②, we want to map it as an Insurance instance, that's how the tragedy happened.
The root is nested Optionals. If we can get the core value regardless the shells, we'll get it done. That's what flatMap does.
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
In the end, I stronly recommed the Java 8 In Action to you if you'd like to study Java8 Systematicly.
Upvotes: 19
Reputation: 4662
They both take a function from the type of the optional to something.
map()
applies the function "as is" on the optional you have:
if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));
What happens if your function is a function from T -> Optional<U>
?
Your result is now an Optional<Optional<U>>
!
That's what flatMap()
is about: if your function already returns an Optional
, flatMap()
is a bit smarter and doesn't double wrap it, returning Optional<U>
.
It's the composition of two functional idioms: map
and flatten
.
Upvotes: 97
Reputation: 16141
What helped me was a look at the source code of the two functions.
Map - wraps the result in an Optional.
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value)); //<--- wraps in an optional
}
}
flatMap - returns the 'raw' object
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value)); //<--- returns 'raw' object
}
}
Upvotes: 8
Reputation: 328785
Use map
if the function returns the object you need or flatMap
if the function returns an Optional
. For example:
public static void main(String[] args) {
Optional<String> s = Optional.of("input");
System.out.println(s.map(Test::getOutput));
System.out.println(s.flatMap(Test::getOutputOpt));
}
static String getOutput(String input) {
return input == null ? null : "output for " + input;
}
static Optional<String> getOutputOpt(String input) {
return input == null ? Optional.empty() : Optional.of("output for " + input);
}
Both print statements print the same thing.
Upvotes: 238