Thursday, May 2, 2024

5 Examples of map() and flatMap() in Java 8 Stream

The map() and flatMap() are prince and princess of functional programming in Java. They are two powerful methods of Stream API which I believe every Java developer should be aware of and should also master it. You can use map() and flatMap() for data transformation, dealing with database operations where you need to convert one object to another while saving or reading from database. You can also use them for parsing and formatting as well as when you want to remove boiler plate code and make your data pipeline concise. The map() function is used in functional programming to transform each element of Stream into another element. 

For example, you can use map to convert a Stream of int to Stream of String. The  key thing to remember here is that map() doesn't modify original stream, it always return a new stream.

Similarly flatMap() function is use to transform each element of Stream into one or more elements and then flatten them into a single Stream. 

For example, if you have Stream of Integers and you want to create another Stream which contains prime factors of each number then you can use the flatMap()function in Java. 

It can take each element from Stream and then return another Stream for them which contains prime factors of that number.  Similar to map(), flatMap() also returns a new stream. They are also lazy which means they will only be evaluated when a terminal operation like reduce() or forEach() is called at the end of pipeline. 

I still remember the first time when I used the map() function to convert one object to another object. I have an object which represented a row in Excel and then I have another object which is used for passing data around the application. 

The names of the fields are different in each object and there were also some derived fields, so I needed to convert the row I read into object using map() function and it was really handy. 

It not only shortened a method of more than 20 lines into 5 lines but also it was more efficient then the traditional for loop I was using, but at the same time it was difficult to read and it took me sometime before I got hand of reading functional code in Java. 

5 Examples of map() and flatMap() functions in Java?

Since a lot of Java developer find understanding difference between map() and flatMap() function difficult, I am sharing examples here which you can practice to improve your understanding of map and flatMap() in Java.

5 Examples of map() and flatMap() in Java 8 Stream


1) Map with lambda expression

In this example, I will show you how to use map() to convert List<String> to List<Integer>.

List<String> hostings = Arrays.asList("Bluehost", "GoDaddy", "HostGator", "AWS");

converting this list to List of integers where each element is length of each element of this list.

List<Integer> length = hostings.stream()
                               .map(s -> s.length())
                               .collect(Collectors.toList());

By the way, its worth remembering that map() can be applied to any Collection not just List because it works with Stream which can be collected to any collection class using the collect() method in Java.

2) Map with method reference

Just like we used lambda expression in previous example, we can method reference in place of lambda expression to make the code more readable. Same transformation can also be done like below code using method reference:

List<Integer> listOfLength = hostings.stream.map(String::length())
                                     .collect(Collectors.toList());

If you look closely, in this example, we have not used lambda expression inside map() function instead of lambda we have passed length() method of String class using double colon operator (::) which is known as method reference in Java. 


3) Converting an Integer Stream to int Stream using mapToIntStream

JDK provides some specialized version of Stream class to deal with primitives. So far, we have seen Stream of reference types, now I'll show you how you can use create Stream of primitives e.g. byte, short, char, int, float, long and double using IntStream, LongStream and DoubleStream

You can use IntStream to create stream of boolean, byte, short, char and int and DoubleStream to create stream of float and double values. Primitive Stream are useful to perform reduction operation e.g. sum, average, median etc.

List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17);
int total = primes.stream.mapToIntStream().sum();


4)  Flattening a Stream

You can use the flatMap() function to flatten an Stream<List<T>> into Stream<T>. It's quite useful to create a big list by combining multiple small lists as shown below:

Stream < List < Integer >> streamOfListOfIntegers = Stream.of(
    Arrays.asList(10, 20),
    Arrays.asList(30, 40),
    Arrays.asList(50)
);

Stream < Integer > streamOfInteger = streamOfListOfIntegers.flatMap(Collection::stream);

You can print all element of this Stream using the forEach() method into console as shown below:

streamOfInteger.forEach(System.out::println);


5) Convert a List of String to Uppercase

You can convert a List of String to another List of String where each element is uppercase of corresponding element using map(String::toUpperCase()) method as shown below:

List<String> hostingProvider = Arrays.asList("Amazon", "Hostgator", "Bluehost", "GoDaddy");
// Convert each element to uppercase using map
List<String> uppercaseHostingProvider = hostingProvider.stream()
                                                      .map(String::toUpperCase)
                                                      .collect(Collectors.toList());


That's all about how to use map() and flatMap() method in Java 8. These are some of the essential operation of functional programming world and they will help you to write better code in Java 8, especially while doing bulk operation with Collection classes. 

Both map() and flatMap() are lazy, immutable and extremely efficient in dealing with large set of data. If you are doing a lot of data transformation, database operations, parsing or formatting, consider using map() and flatMap() to change data from one form to another. 

Other Java Functional Programming articles you may like
  • How to sort the may by values in Java 8? (example)
  • Difference between map() and flatMap in Java 8 (answer)
  • How to use Stream class in Java 8 (tutorial)
  • How to format/parse the date with LocalDateTime in Java 8? (tutorial)
  • What is the default method in Java 8? (example)
  • How to join String in Java 8 (example)
  • Difference between abstract class and interface in Java 8? (answer)
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to sort the map by keys in Java 8? (example)
  • 15 Java Stream and Functional Programming interview questions (list)
  • How to convert List to Map in Java 8 (solution)
  • 10 examples of Optional in Java 8? (example)

All the best with your Java functional programming journey.  If you have any question or doubt, feel free to ask in comments. 

1 comment:

  1. How much data map() can handle in Java? can it process 1 million rows in memory?

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.