Disclosure: This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided in this article.
Hello, folks! If you are learning functional programming in Java and want to learn how to use map, filter, and collect methods in Java then you have come to the right place.
In the past, I have shared the best Java functional programming courses as well as some Java books on Lambda and Stream, and today, I am going to teach you how you can use map, filter, and collect() methods to create your stream pipeline to transform your data from one form to other.
Even though I have previously blogged about both the map() and filter(), I am writing this post again to expand on the concept in a layman's language to provide a better understanding for my readers and fellow Java developers.
The map() function is a method in the Stream class that represents a functional programming concept. In simple words, the map() is used to transform one object into another by applying a function.
That's the reason the Stream.map(Function mapper)
takes a function as an argument. For example, by using the map()
function, you can convert a list of String into a List of Integer by applying the Integer.valueOf() method to each String on the input list.
All you need is a mapping function to convert one object to the other. Then, the map() function will do the transformation for you. It is also an intermediate Stream operation which means you can call other Stream methods, like a filter, or collect on this to create a chain of transformations.
Now, coming to the filter method, as its name suggests, it filters elements based upon a condition you gave it. For example, if your list contains numbers and you only want numbers, then you can use the filter method to only select a number that is fully divisible by two.
The filter method essentially selects elements based upon a condition you provide. That's the reason that the filter (Predicate
condition) accepts a Predicate object, which provides a function that is applied to a condition. If the condition evaluates true, then the object is selected. Otherwise, it will be ignored.
Similar to the map, the filter is also an intermediate operation which means you can call other Stream methods after calling the filter.
The filter()
the method is also lazy which means that it will not be evaluated until you call a reduction method, like collect, and it will stop as soon as it reaches the target.
If you are not familiar with Stream behavior, I suggest you check out Learn Java Functional Programming with Lambdas & Streams by Ranga Rao Karnam on Udemy, which explains Stream fundamentals in good detail.
1. How to write functional code in Java using Lambda and Stream
You need a good example to understand any new concept. That's why you are reading this article. Since String and Integer are the most common data type in Java, I have chosen an example which is both simple and interesting.
I have a list of String: numbers like {"1", "2", "3", "4", "5", "6"}
. I want to process this list and need another List of Integer with just even numbers.
In order to find the even numbers, I first need to convert a List of String to a List of Integer. For that, I can use the map() method of java.util.Stream class. But, before that, we need a Stream as a map() as defined in the java.util.stream class.
This is not difficult at all since you can get the stream from any collection, like List or Set, by calling the stream() method, which is defined in the java.util.Collection
interface.
The map(Function mapper)
method takes a Function, technically speaking, an object of java.util.function.Function interface. This function is then applied to each element of Stream to convert it into the type you want.
Since we need to convert a String to an Integer, we can pass either the Integer.parseInt()
or Integer.valueOf()
method to the map() function.
I have chosen the valueOf()
method because of the reasons I mentioned in the parseInt vs valueOf article, i.e. performance and caching. By the way, it's not just me. Even Joshua Bloch has advised preferring static factory methods like valueOf()
over constructor in Effective Java.
The map()
will then return a Stream of Integer which contains both even and odd numbers. To select just even numbers, we can use the filter() method.
It takes a predicate object which is technically a function to convert an object to boolean. We pass an object and it will return true or false. The filter, then, uses that information to include the object in the result stream.
So, to include only even numbers, we call filter( number -> number%2==0)
which means each number will be divided by two, and if there is no remainder, then it will be selected. This is the same logic we have used while solving coding problems to check if a given number is even or odd in Java.
We are almost done. But, so far, we only have the Stream of even integers --- not the List of even Integers and that's why we need to use them.
Since we need a List, I called **collect(Collectors.toList())**
, which will accumulate all even numbers into a List and return.
Now, you may be thinking: how does it know to return List of Integer? Well, we need to get that information by Type inference, because we have already specified that information by storing the result into a List<Integer>
.
If you want to know more about type inference in a lambda expression,The Complete Java MasterClassis a good place to start.
2. Java 8 Map + Filter + Collect Example
Here is the Java program to implement whatever I have said in the above section. You can run this program in IDE or from the command line and see the result.
You can also experiment with using more map()
functions or more filter()
calls to make the composition longer and more sophisticated. You can even play with the collect()
method to collect the result in a list, set, map or any other collection.
You can see that the original list contains numbers from 1 to 6, and the filtered list only contains even numbers, I mean, 2, 4, and 6.
The most important code in this example is the following four lines of Stream processing code:
This code is starting with a map, then a filter, and finally a collect. You may be wondering whether the order will matter or not. Well, it does.
Since our filter condition requires an int variable we first need to convert Stream of String to Stream of Integer. That's why we called the map() function first.
Once we have the Stream of Integer, we can apply maths to find out even numbers. We passed that condition to the filter method. If we needed to filter on String, like select all string which has length > 2
, then we would have called filter before map.
That's all about how to use map and filter in Java 8. We have seen an interesting example of how we can use the map to transform an object to another and how to use the filter to select an object-based upon condition. We have also learned how to compose operations on stream to write code that is both clear and concise.
Further Learning
The Complete Java MasterClass
From Collections to Streams in Java 8 Using Lambda Expressions
Java SE 8 for Programmers (book)
Refactoring to Java 8 Streams and Lambdas Self- Study Workshop
Other Java tutorials you may like
If you are interested in learning more about new features of Java 8, here are my earlier articles covering some of the important concepts of Java 8:
- The 2020 Java Developer RoadMap (see)
- 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)
- 10 Courses to learn Java in-depth (courses)
- How to format/parse the date with LocalDateTime in Java 8? (tutorial)
- 5 Books to Learn Java 8 from Scratch (books)
- 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 Optionals in Java 8? (example)
Thanks for reading this article so far. If you find this Java tutorial useful then please share it with your friends and colleagues. If you have any questions or feedback, please drop a note.
P.S.- If you are serious about improving your functional programming skills in Java and wan to learn more about Java Stream API, I strongly recommend you to checkout Learn Java Functional Programming with Lambdas & Streams course by Ranga Rao Karnam on Udemy, which explains Stream fundamentals in good detail.