Java 8 Streams: An Intro to Filter, Map and Reduce Operations Learn more on Java with our tutorial Bridging Android and Java in Android Development on SitePoint. In this tutorial, we would be looking at the various examples of using streams introduced in Java 8 to create a Map from a List of values. I have been working with Java 8 for quite a while and have found streams extremely useful.
In this post, we will see how to convert Stream to a Map in Java.
1. Converting Stream of String[]
The Java 8 Stream API can be used to construct maps by obtaining stream from static factory methods like
Stream.of()
or Arrays.stream()
and accumulating the elements of the stream into a new map using collectors.
We know that a Stream of
String[]
is essentially a sequence of items, not a sequence of key/value pairs. To extract a Map out of it, we can use Collectors.toMap()
method where we provide proper mapping functions to specify how to extract keys and values from elements of the stream.
2
4
6
8
10
12
14
16
18
20
22
24
26
28
|
importjava.util.stream.Collectors;
{
privatestaticStream<String[]>getMapStream()
returnStream.of(newString[][]{
{'BIKE','Harley Davidson'}
}
// Program to convert Stream to a Map in Java 8
{
Stream<String[]>stream=getMapStream();
// construct a new map from the stream
stream.collect(Collectors.toMap(e->e[0],e->e[1]));
System.out.println(vehicle);
}
|
Output:
{CAR=Audi, BIKE=Harley Davidson}
{CAR=Audi, BIKE=Harley Davidson}
To initialize a map with different types for key and value, we can do:
2
|
Map<String,Integer>map=Stream.of(newObject[][]{{'A',65},{'B',66}})
e->(Integer)e[1]));
|
We could also adapt a Collector to perform an additional finishing transformation. For example, we could adapt the
toMap()
collector to always produce an immutable map with:
2
|
.collect(Collectors.collectingAndThen(Collectors.toMap(e->e[0],e->e[1]),
|
2. Converting Stream of Map.Entry to Map
Method references in Java 8 made it very easy to construct maps from stream of
Map.Entry
as shown below:
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
|
importjava.util.Map;
importjava.util.stream.Stream;
classMapUtils
// Function to get Stream of map mappings
privatestaticStream<Map.Entry<String,String>>getMapStream()
Map<String,String>vehicle=newHashMap<>();
vehicle.put('BIKE','Harley Davidson');
returnvehicle.entrySet().stream();
publicstaticvoidmain(Stringargs[])
// get map stream
Stream<Map.Entry<String,String>>stream=getMapStream();
// construct a new map from the stream
Map<String,String>map=stream.collect(Collectors.toMap(
Map.Entry::getValue));
System.out.println(map);
}
|
Output:
{CAR=Audi, BIKE=Harley Davidson}
{CAR=Audi, BIKE=Harley Davidson}
As seen before, to get an immutable map we can do:
2
4
6
8
10
12
14
16
18
20
22
24
26
|
importjava.util.Map;
importjava.util.stream.Stream;
classMapUtils
// Function to get Stream of map mappings
staticStream<AbstractMap.SimpleEntry<String,String>>getMapStream()
returnStream.of(
newAbstractMap.SimpleEntry<>('USA','Washington DC'),
}
// Program to convert Stream to a Map in Java 8
{
Map<String,String>capital=getMapStream()
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey,
}
|
Output:
{USA=Washington DC, UK=London}
{USA=Washington DC, UK=London}
2.
AbstractMap.SimpleImmutableEntry
â
![Java stream map example Java stream map example](/uploads/1/2/3/3/123324657/913836660.png)
2
4
6
8
10
12
14
16
18
20
22
24
26
28
|
importjava.util.Map;
importjava.util.stream.Stream;
classMapUtils
// Function to get Stream of map mappings
Stream<AbstractMap.SimpleImmutableEntry<String,String>>getMapStream()
returnStream.of(
newAbstractMap.SimpleImmutableEntry<>('USA','Washington DC'),
newAbstractMap.SimpleImmutableEntry<>('UK','London'));
publicstaticvoidmain(Stringargs[])
// construct a new map from the stream
getMapStream().collect(Collectors.toMap(
AbstractMap.SimpleImmutableEntry::getValue));
System.out.println(capital);
}
|
Output:
{USA=Washington DC, UK=London}
{USA=Washington DC, UK=London}
(4 votes, average: 5.00 out of 5)
Thanks for reading.
Please use our online compiler to post code in comments. To contribute, get in touch with us.
Like us? Please spread the word and help us grow. Happy coding ?
Like us? Please spread the word and help us grow. Happy coding ?
The Java Stream API provides a more functional programming approach to iterating and processing elements of e.g. a collection. The Java Stream API was added to Java in Java 8. This tutorial is only intended to explain how to use the Java Stream API in the context of the Java Collection API. For a more in-depth explanation of the Java Stream API, see my Java Stream API Tutorial.
Streams are designed to work with Java lambda expressions. Many of the examples in this text will use lambda expressions, so if you don't already know them, you should read up on them before reading this text.
Obtaining a Stream From a Collection
You obtain a stream from a collection by calling the
stream()
method of the given collection. Here is an example of obtaining a stream from a collection:
First a
List
of strings is created and three strings are added to it. Then a Stream
of strings is obtained by calling the items.stream()
method. This is similar to how you obtain an Iterator
by calling the items.iterator()
method, but a Stream
is a different animal than an Iterator
.
Stream Processing Phases
Once you have obtained a
Stream
instance from a Collection
instance, you use that stream to process the elements in the collection.
Processing the elements in the stream happens in two steps / phases:
- Configuration
- Processing
First the stream is configured. The configuration can consist of filters and mappings. These are also referred to as non-terminal operations.
Second, the stream is processed. The processing consists of doing something to the filtered and mapped objects. No processing takes place during the configuring calls. Not until a processing method is called on the stream. The stream processing methods are also referred to as terminal operations.
Stream.filter()
You filter a stream using the
filter()
method. Here is a stream filtering example:
The
filter()
method takes a Predicate
as parameter. The Predicate
interface contains a function called test()
which the lambda expression passed as parameter above is matched against. In other words, the lambda expression implements the Predicate.test()
method.
The
test()
method is defined like this:
It takes a single parameter and returns a
boolean
. If you look at the lambda expression above, you can see that it takes a single parameter item
and returns a boolean - the result of the item.startsWith('o')
method call.
When you call the
filter()
method on a Stream
, the filter passed as parameter to the filter()
method is stored internally. No filtering takes place yet.
The parameter passed to the
filter()
function determines what items in the stream should be processed, and which that should be excluded from the processing. If the Predicate.test()
method of the parameter passed to filter()
returns true
for an item, that means it should be processed. If false
is returned, the item is not processed.
Stream.map()
It is possible to map the items in a collection to other objects. In other words, for each item in the collection you create a new object based on that item. How the mapping is done is up to you. Here is a simple Java stream mapping example:
This example maps all strings in the
items
collection to their uppercase equivalents.
Again, this example doesn't actually perform the mapping. It only configures the stream for mapping. Once one of the stream processing methods are invoked, the mapping (and filtering) will be performed.
Stream.collect()
The
collect()
method is one of the stream processing methods on the Stream
interface. When this method is invoked, the filtering and mapping will take place and the object resulting from those actions will be collected. Here is a stream.collect()
example:
This example creates a stream, adds a filter, and collects all object accepted by the filter in a
List
. The filter only accepts items (strings) which start with the character o
. The resulting List
thus contains all strings from the items
collection which starts with the character o
.
Stream.min() and Stream.max()
The
min()
and max()
methods are stream processing methods. Once these are called, the stream will be iterated, filtering and mapping applied, and the minimum or maximum value in the stream will be returned.
Here is a Java
Stream.min()
example:
The
min()
and max()
methods return an Optional
instance which has a get()
method on, which you use to obtain the value. In case the stream has no elements the get()
method will return null.
The
min()
and max()
methods take a Comparator
as parameter. The Comparator.comparing()
method creates a Comparator
based on the lambda expression passed to it. In fact, the comparing()
method takes a Function
which is a functional interface suited for lambda expressions. It takes one parameter and returns a value.
Stream.count()
The
count()
method simply returns the number of elements in the stream after filtering has been applied. Here is an example:
This example iterates the stream and keeps all elements that start with the character
t
, and then counts these elements.
The
count()
method returns a long
which is the count of elements in the stream after filtering etc.
Stream.reduce()
The
reduce()
method can reduce the elements of a stream to a single value. Here is an example:
The
reduce()
method takes a BinaryOperator
as parameter, which can easily be implemented using a lambda expression. The BinaryOperator.apply()
method is the method implemented by the lambda expression above. This method takes two parameters. The acc
which is the accumulated value, and item
which is an element from the stream. Thus, the value created by the reduce()
function is the accumulated value after processing the last element in the stream. In the example above, each item is concatenated to the accumulated value. This is done by the lambda expression implementing the BinaryOperator
.
The
reduce()
method taking a BinaryOperator
as parameter returns an Optional
. In case the stream contains no elements, the Optional.get()
returns null. Otherwise it returns the reduced value.
There is another
reduce()
method which takes two parameters. It takes an initial value for the accumulated value, and then a BinaryOperator
. Here is an example:
This example takes an empty string as initial value, and then the same lambda expression as the previous example. This version of the
reduce()
method returns the accumulated value directly, and not an Optional
. If the stream contains no elements, the initial value will be returned.
The
reduce()
method can be combined with the filter()
method too. Here is an example:
This example keeps all elements that start with the character
o
, and then reduce these elements into a single value.