Wednesday, August 7, 2019

Java 8 Optional flatMap() Method Example

1.Overview


In this tutorial, We'll learn how to wrap all nested Optional values into a Direct Map instead of having hierarchies.
You get a better understanding once you see the example.

You will be learning today syntax, examples and its internal implementation part.

This is part of our Optional Method series course.

API Description:

If a value is present, returns the result of applying the given Optional-bearing mapping function to the value, otherwise returns an empty Optional. This method is similar to map(Function), but the mapping function is one whose result is already an Optional, and if invoked, flatMap does not wrap it within an additional Optional.



If you do not understand the above note no worries. By the end of this article, you will be cleared all your doubts.

2. flatMap() Syntax


Below is the flatMap() method syntax in Optional class.

public <U> Optional<U> flatMap(Function<? super T,? extends Optional<? extends U>> mapper)

This is an instance method and must be invoked on the Optional instance. This function takes Function as an argument and returns the Optional object.
Function is a Functional Interface which has U apply(T t) functional method.

3. Java 8 flatMap() Example


Example program on flatMap() method. Here create first one Optional instance optional1 with string value "Hello Java 8" and next created another Optional instance optional2 with optional1.

Now, optional2 has an optional value of optional1. optional2 type if Optional. This is called Two levels nested Optional instance.

package com.java.w3schools.blog.java8.optional;

import java.util.Optional;

/**
 * Java 8 Optional flatMap() Method Example
 * 
 * @author venkatesh
 *
 */
public class OPtionalFlatMapExample {
     
     public static void main(String[] args) {
         
         Optional<String> optional1 = Optional.of("Hello Java 8");
         Optional<Optional<String>> optional2 = Optional.of(optional1);
         
         System.out.println("Optional2 value : " + optional2);
         
         Optional<String> output = optional2.flatMap(value -> value.map(String::toLowerCase));
         
         System.out.println("output value : " + output);
     }
}

Output:

Optional2 value : Optional[Optional[Hello Java 8]]
output value : Optional[hello java 8]

After calling the flatMap() method we see that output is converted into lower case and removed the nested Optional.

3. Nested Levels Optional Example:


Now creating a 3 level nested Optional object. Checking if the string contains "Java 8" then return Optional instance with content "Yes, Java 8 is found.".


public class OPtionalFlatMapExample2 {
      
      public static void main(String[] args) {
          
          Optional<String> optional1 = Optional.of("Hello Java 8");
          Optional<Optional<String>> optional2 = Optional.of(optional1);
          Optional<Optional<Optional<String>>> optional3 = Optional.of(optional2);
          
          System.out.println("optional3 value : " + optional3);
          
          Optional<String> output = optional3.flatMap(value -> value.flatMap(v -> {
              if (v.get().contains("Java 8")) {
                  return Optional.of("Yes, Java 8 is found.");
              }
              return Optional.empty();
          }));
          
          System.out.println("output value : " + output);
      }
}

Output:

optional3 value : Optional[Optional[Optional[Hello Java 8]]]
output value : Optional[Yes, Java 8 is found.]

4. Empty optional example:


public class OPtionalFlatMapExample3 {
     
     public static void main(String[] args) {
        
        Optional<String> nullOptional = Optional.ofNullable(null);
        Optional<String> output = nullOptional.flatMap(value -> Optional.of("No Value"));
        
        System.out.println("output value : " + output);
     }
}

Output:

output value : Optional.empty

5. flatMap() Internal Implementation


Let us take a look at how it is implemented internally.

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        @SuppressWarnings("unchecked")
        Optional<U> r = (Optional<U>) mapper.apply(value);
        return Objects.requireNonNull(r);
    }
}

Explanation:

This method internally calls the mapper.apply(value) functional method of Function Functional Interface. If the mapper is null then it will throw NullPointerException. If Optional is not having value then it returns empty Optional by calling empty() method.

6. Conclusion


In this article, We've seen how to use flatMap() method when we have nested Optional objects. flatMap(Function f) accepts only Function Functional Interface. 

Note: This method is useful if and only Optional has nested Optional objects. Suggested not to use in other scenarios and use map() method.

Shown the example programs on each possible case. If we pass the null to flatMap() method then it will throw NullPointerException.

Explained how it is implemented internally and step by step explanation to its internal code.

All the code shown is over GitHub.
API Ref

No comments:

Post a Comment