Sunday, July 21, 2019

Java Optional Tips and Tricks



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 OptionalflatMap() is a bit smarter and doesn't double wrap it, returning Optional<U>
https://www.baeldung.com/java-difference-map-and-flatmap
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());
https://winterbe.com/posts/2015/03/15/avoid-null-checks-in-java/
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


  1. Do not declare any instance variable of type Optional.
  2. Use null to indicate optional data within the private scope of a class.
  3. Use Optional for getters that access the optional field.
  4. Do not use Optional in setters or constructors.
  5. 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
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 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  OptionalIntOptionalLong, 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 theOptionalinstance as aStreamby applyingOptional.stream()method. This is useful when you need to chain the Optional API with the Stream API. This method creates aStreamof one element or an emptyStream(ifOptionalis not present). Further, we can use all the methods that are available in the Stream API. 
Avoid:
// AVOID
public List<Product> getProductList(List<String> productId) {
    return productId.stream()
        .map(this::fetchProductById)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(toList());
}
public Optional<Product> fetchProductById(String id) {
    return Optional.ofNullable(...);
}
Prefer:
// PREFER
public List<Product> getProductList(List<String> productId) {
    return productId.stream()
        .map(this::fetchProductById)
        .flatMap(Optional::stream)
        .collect(toList());
}
public Optional<Product> fetchProductById(String id) {
    return Optional.ofNullable(...);
}
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"));

  1. IntStream stream = Stream.range(‐100100);   
  2. 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 T -> Optional<U>?
Your result is now an Optional<Optional<U>>!
That's what flatMap() is about: if your function already returns an OptionalflatMap() 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
    }
}


Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts