https://stackoverflow.com/questions/30864583/java-8-difference-between-optional-flatmap-and-optional-map
Use
map
if the function returns the object you need or flatMap
if the function returns an Optional
. For example:
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>
The flatMap() method first flattens the input Stream of Streams to a Stream of Strings (for more about flattening, see the article). Thereafter it works similarly to the map() method.
List<String> filteredList = listOfOptionals.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
1
2
3
| List<String> filteredList = listOfOptionals.stream() .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty()) .collect(Collectors.toList()); |
Alternatively, you could apply the same approach using a different way of converting an Optional to Stream:
1
2
3
| List<String> filteredList = listOfOptionals.stream() .flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty)) .collect(Collectors.toList()); |
List<String> filteredList = listOfOptionals.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
Resolving a deep nested path in this structure can be kinda awkward. We have to write a bunch of null checks to make sure not to raise a
NullPointerException
:Outer outer = new Outer();
if (outer != null && outer.nested != null && outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}
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. Null checks are automatically handled under the hood.Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo)
.ifPresent(System.out::println);
An alternative way to achieve the same behavior is by utilizing a supplier function to resolve the nested path:
Outer obj = new Outer();
resolve(() -> obj.getNested().getInner().getFoo());
.ifPresent(System.out::println);
Calling
obj.getNested().getInner().getFoo())
might throw a NullPointerException
. In this case the exception will be caught and the method returns Optional.empty()
.public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
}
catch (NullPointerException e) {
return Optional.empty();
}
}
https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html
- Do not declare any instance variable of type
Optional
. - Use
null
to indicate optional data within the private scope of a class. - Use
Optional
for getters that access the optional field. - Do not use
Optional
in setters or constructors. - Use
Optional
as a return type for any other business logic methods that have an optional result.
Throwing an exception is a common pattern in Java API to return null in case a value is not present. Integet.parseInt(String) will throw NumberFormatException in case supplied argument is invalid.
https://mp.weixin.qq.com/s/irt36Wz_Ap2-SYzm1ajAEQ
http://dolszewski.com/java/java-8-optional-use-cases/
https://reversecoding.net/java-8-optional-replace-get-examples/
flatMap() it’s similar to map() but should be used when the transformation function returns an
Optional
of some <T>
. flatMap() executes the transformation function like the map() but instead of returning Optional<Optional<T>>
if will just return Optional<T>
. Basically it flattens the Optional
.
map() is a method used to apply a transformation to the content of the
Optional
if it’s present.Optional
is a highly underrated feature, and one that has the potential to remove a lot of those NullPointerExceptions
that can plague us. It’s particularly useful at the boundaries of code (either APIs you’re using or APIs you’re exposing) as it allows you and your calling code to reason about what to expect.
Optional should only be used for return types
…not parameters and not fields. Read this blog post to see a pragmatic approach to using Optional. Fortunately, IntelliJ IDEA lets you turn on an inspection to check you’re following these recommendations
…not parameters and not fields. Read this blog post to see a pragmatic approach to using Optional. Fortunately, IntelliJ IDEA lets you turn on an inspection to check you’re following these recommendations
You should not simply call get()
The strength of Optional is to express that this value might be empty, and allow you to cater for that case. Therefore, it’s important to check if there is a value before doing anything with it. Simply calling
The strength of Optional is to express that this value might be empty, and allow you to cater for that case. Therefore, it’s important to check if there is a value before doing anything with it. Simply calling
get()
without checking isPresent()
first is likely to lead to a null pointer at some point. https://dzone.com/articles/using-optional-correctly-is-not-optional
Optional is intended to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result," and using null for such was overwhelmingly likely to cause errors.
Item 1: Never Assign Null to an Optional Variable
Item 2: Ensure That an Optional Has a Value Before Calling Optional.get()
Item 3: When No Value Is Present, Set/Return an Already-Constructed Default Object Via the Optional.orElse() Method
Item 8: Consume an Optional if it Is Present. Do Nothing if it Is Not Present. This Is a Job For Optional.ifPresent().
Item 9: Consume an Optional if it Is Present. If it Is Not Present, Then Execute an Empty-Based Action. This Is a Job For Optional.ifPresentElse(), Java 9.
Item 10: When the Value Is Present, Set/Return That Optional. When No Value Is Present, Set/Return the Other Optional. This Is a Job For Optional.or(), Java 9.
Item 11: Optional.orElse/ orElseXXX Are a Perfect Replacement for isPresent()-get() Pair in Lambdas
Item 12: Avoid Chaining Optional's Methods With the Single Purpose of Getting a Value
Item 13: Do Not Declare Any Field of Type Optional
Do not use Optional in methods (including setters) or constructors arguments.
Remember thatOptional was not intended to be used for fields and it doesn't implementSerializable. TheOptionalclass is definitively not intended for use as a property of a Java Bean.
Item 14: Do Not Use Optional in Constructors Arguments
I think routinely using it as a return value for getters would definitely be over-use.
Item 15: Do Not Use Optional in Setters Arguments
Item 19: Do Not Confuse Optional.of() and Optional.ofNullable()
Confusing or mistakenly using Optional.ofinstead ofOptional.ofNullable, or vice-versa, can lead to unpleasant issues. As a key here, keep in mind thatOptional.of(null)will throwNullPointerException, whileOptional.ofNullable(null)will result in an Optional.empty.
Unless you have a specific need for boxed primitives, avoid
Optional<
T
>
and select the non-generic OptionalInt
, OptionalLong
, or OptionalDouble
.
Boxing and unboxing are expensive operations that are prone to induce performance penalties. In order to eliminate this risk, we can rely on
OptionalInt
,OptionalLong
, and OptionalDouble
. These are wrappers for primitive typesint
,long,
anddouble
.
Item 21: There Is No Need to Unwrap Optionals for Asserting Equality
Item 24: Do We Need to Chain the Optional API With the Stream API?
If so, we then use the
Optional.stream()
method.
Starting with Java 9, we can treat the
Optional
instance as aStream
by applyingOptional.stream()
method. This is useful when you need to chain the Optional API with the Stream API. This method creates aStream
of one element or an emptyStream
(ifOptional
is not present). Further, we can use all the methods that are available in the Stream API.
Avoid:
Prefer:
Practically,
Optional.stream()
allows us to replacefilter()
and map()
with flatMap()
.
Item 25: Avoid Using Identity-Sensitive Operations on Optionals
This includes reference equality (==), identity hash-based, or synchronization.
Item 26: Return a boolean If The Optional Is Empty. Prefer Java 11, Optional.isEmpty()
How should Optional NOT be used?
Optional is not meant to be used in these contexts, as it won't buy us anything:
- in the domain model layer (not serializable)
- in DTOs (same reason)
- in input parameters of methods
- in constructor parameters
https://blog.indrek.io/articles/chaining-optionals-in-java-8/
https://stackify.com/optional-java/
User result = Optional.ofNullable(user).orElse(user2);
map() applies the Function argument to the value, then returns the result wrapped in an Optional. This makes it possible to apply and chain further operations on the response – such orElse() here.
By comparison, flatMap() also takes a Function argument that is applied to an Optional value, and then returns the result directly.
Java 9 adds three more methods to the Optional class: or(), ifPresentOrElse() and stream().
The or() method is similar to orElse() and orElseGet() in the sense that it provides alternate behavior if the object is empty. In this case, the returned value is another Optional object that is produced by a Supplier argument
The ifPresentOrElse() method takes two arguments: a Consumerand a Runnable. If the object contains a value, then the Consumeraction is executed; otherwise, the Runnable action is performed.
This method can be useful if you want to perform an action using the value if one is present, or simply keep track of whether a value was defined or not:
Optional.ofNullable(user).ifPresentOrElse( u -> logger.info("User is:" + u.getEmail()), () -> logger.info("User not found"));
Lastly, the new stream() method allows you to benefit from the extensive Stream API by transforming the instance to a Streamobject. This will be an empty Stream if no value is present, or a Stream containing a single value – in case the Optional contains a non-null value.
User user = new User("john@gmail.com", "1234"); List<String> emails = Optional.ofNullable(user) .stream() .filter(u -> u.getEmail() != null && u.getEmail().contains("@")) .map( u -> u.getEmail()) .collect(Collectors.toList());
Optional is not Serializable
If you do need to serialize an object that contains an Optionalvalue, the Jackson library provides support for treating Optionalsas ordinary objects. What this means is that Jackson treats empty objects as null and objects with a value as fields containing that value. This functionality can be found in the jackson-modules-java8 project.
Another situation when it’s not very helpful to use the type is as a parameter for methods or constructors. This would lead to code that is unnecessarily complicated:
User user = new User("john@gmail.com", "1234", Optional.empty());
Instead, it’s much easier to use method overloading to handle parameter which aren’t mandatory.
The intended use of Optional is mainly as a return type. After obtaining an instance of this type, you can extract the value if it’s present or provide an alternate behavior if it’s not.
One very useful use-case of the Optional class is combining it with streams or other methods that return an Optional value to build fluent APIs.
User user = users.stream().findFirst().orElse(new User("default", "1234"));
- IntStream stream = Stream.range(‐100, 100);
- OptionalInt opt = stream.max(Comparator.naturalOrder());
This
max()
method returns a result wrapped in an OptionalInt
. Let's explore what would have been wrong if it had been an int.
A problem arises if the stream on which we compute this max turns out to be empty. Remember that a real‐life stream can be the result of a complex computation, involving mappings, filterings, selections, and the like. It can also be the result of the splitting of a main stream into substreams distributed among the several cores of a CPU for parallel computation. So, an empty stream is something that can definitely happen, even when we do not expect it.
https://stackoverflow.com/questions/30864583/java-8-difference-between-optional-flatmap-and-optional-map
Use
map
if the function returns the object you need or flatMap
if the function returns an Optional
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
Your result is now an
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
.
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
}
}