Java Stream Map Example
1. Introduction
Java has provided Stream API to iterate and process elements in a collection with a declarative style since version 8. A stream is a sequence of objects that can be constructed via the default java.util.Collection.stream() method, static java.util.Arrays.stream() method, static java.nio.file.Files.lines() method, etc. Streams don’t change the element data. Stream API provides intermediate and terminal operations to process elements and return a result.
We can use its map method to transform elements in a collection of objects without using a loop statement. The map method is an intermediate operation which transforms a stream into another stream via a function. Here is the syntax:
/* Returns a stream consisting of the results of applying the given function to the elements of this stream. Type Parameters: R - The element type of the new stream Parameters: mapper - a non-interfering, stateless function to apply to each element */ <R> Stream<R> map(Function<? super T, ? extends R> mapper)
In this example, I will demonstrate:
- Three ways to use the
mapmethod: lambda expression, method reference, andFunction - Chain the
mapmethod with intermediate operations:filter,peek, etc - Close the
mapmethod with terminal operations:foreach,count,collect,toArray, etc
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- Junit 4.12
3. Maven Project
3.1 Dependencies
I will include Junit in the pom.xml.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>java-stream-map-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
3.2 Demo POJO
I will create a DemoPOJO which will be used to transform data.
DemoPOJO.java
package jcg.zheng.demo;
public class DemoPOJO {
private int id;
private String name;
public DemoPOJO(int id, String name) {
super();
this.name = name;
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DemoPOJO other = (DemoPOJO) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public int nameWordCount() {
return name.length();
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
4. JUnit Test
4.1 TestBase
In this step, I will create a TestBase class which has two lists and two methods.
lowerCaseStrings– a list with three strings:"mary","something","end"testObjects– a list with fourDemoPOJOobjectsvalidateTestObject– validates the test objectsvalidateUpperCaseTransform– validates the test strings
TestBase.java
package jcg.zheng.demo.stream;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import jcg.zheng.demo.DemoPOJO;
public class TestBase {
protected List<String> lowerCaseStrings = Arrays.asList("mary", "something", "end");
protected List<DemoPOJO> testObjects = Arrays.asList(new DemoPOJO(10, "Mary"), new DemoPOJO(20, "Zheng"),
new DemoPOJO(30, "Tom"), new DemoPOJO(40, "Johnson"));
protected void validateTestObject(List<String> names) {
assertTrue(names.contains("Mary"));
assertTrue(names.contains("Zheng"));
assertTrue(names.contains("Tom"));
assertTrue(names.contains("Johnson"));
}
protected void validateUpperCaseTransform(List<String> allUppercase) {
assertTrue(allUppercase.contains("MARY"));
assertTrue(allUppercase.contains("SOMETHING"));
assertTrue(allUppercase.contains("END"));
}
}4.2 StreamMapTest
In this step, I will create a StreamMapTest class which shows three ways to create a function used in a map method.
string_function()– it testsStream.mapwith aFunctionfor aStringobject.string_lambda()– it testsStream.mapwith a lambda expression for aStringobject.string_method_reference()– it testsStream.mapwith a method reference shorthand for aStringobject.object_function()– it testsStream.mapwith aFunctionfor aDemoPOJOobject.object_lambda()– it testsStream.mapwith a lambda expression for aDemoPOJOobject.object_method_reference()– it testsStream.mapwith a method reference shorthand for aDemoPOJOobject.
StreamMapTest.java
package jcg.zheng.demo.stream;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.junit.Test;
import jcg.zheng.demo.DemoPOJO;
public class StreamMapTest extends TestBase {
@Test
public void string_function() {
Function<String, String> toUpper = String::toUpperCase;
List<String> allUppercase = lowerCaseStrings.stream().map(toUpper).collect(Collectors.toList());
validateUpperCaseTransform(allUppercase);
}
@Test
public void string_lambda() {
List<String> allUppercase = lowerCaseStrings.stream().map(n -> n.toUpperCase()).collect(Collectors.toList());
validateUpperCaseTransform(allUppercase);
}
@Test
public void string_method_reference() {
List<String> allUppercase = lowerCaseStrings.stream().map(String::toUpperCase).collect(Collectors.toList());
validateUpperCaseTransform(allUppercase);
}
@Test
public void object_lambda() {
List<String> names = testObjects.stream().map(obj -> obj.getName()).collect(Collectors.toList());
validateTestObject(names);
}
@Test
public void object_function() {
Function<DemoPOJO, Integer> transform = DemoPOJO::nameWordCount;
List<Integer> nameCounts = testObjects.stream().map(transform).collect(Collectors.toList());
nameCounts.forEach(s -> System.out.println(s));
}
@Test
public void object_methodReference() {
List<String> names = testObjects.stream().map(DemoPOJO::getName).collect(Collectors.toList());
validateTestObject(names);
}
}
Output
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.stream.StreamMapTest 4 5 3 7 Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.144 sec Results : Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
4.3 StreamMap_IntermediateOperationTest
In this step, I will create a StreamMap_IntermediateOperationTest class which chains the map method to Stream‘s intermediate operations before and after.
map_filter()– it chainsmapto afilteroperation.filter_map()– it chainsfilterto amapoperation.map_map()– it chainsmapto anothermapoperation.map_peek()– it chainsmapto apeekoperation.
StreamMap_IntermediateOperationTest.java
package jcg.zheng.demo.stream;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.junit.Test;
public class StreamMap_IntermediateOperationTest extends TestBase {
@Test
public void filter_map() {
Predicate<String> shortName = name -> name.length() < 4;
List<String> shortNames = lowerCaseStrings.stream().filter(shortName).map(String::toUpperCase)
.collect(Collectors.toList());
assertEquals("END", shortNames.get(0));
}
@Test
public void map_filter() {
Predicate<String> shortName = name -> name.length() < 4;
List<String> shortNames = lowerCaseStrings.stream().map(String::toUpperCase).filter(shortName)
.collect(Collectors.toList());
assertEquals("END", shortNames.get(0));
}
@Test
public void map_map() {
Function<String, String> prefix = n -> "PRE_" + n;
lowerCaseStrings.stream().map(prefix).map(String::toUpperCase).forEach(e -> System.out.println(e));
}
@Test
public void map_peek() {
//peek is for debugging purpose to see the elements in the Stream
lowerCaseStrings.stream().map(String::toUpperCase).peek(e -> System.out.println(e)).collect(Collectors.toList());
}
}
Output of mvn test -Dtest=StreamMap_IntermediateOperationTest
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.stream.StreamMap_IntermediateOperationTest MARY SOMETHING END PRE_MARY PRE_SOMETHING PRE_END Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.209 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
4.4 StreamMap_TerminalOperationTest
In this step, I will create a StreamMap_TerminalOperationTest class which chains the map method to a Stream’s terminal operation which produces a result or side-effect.
map_collect()– it returns a list with acollectoperation.map_filter_count()– it chainsmapto afilteroperation and returns the count.map_foreach()– it terminates stream with aforeachoperationmap_toArray()– it returns an object array with atoArrayoperation
StreamMap_TerminalOperationTest.java
package jcg.zheng.demo.stream;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
public class StreamMap_TerminalOperationTest extends TestBase {
@Test
public void map_collect() {
List<String> allUppercase = lowerCaseStrings.stream().map(String::toUpperCase).collect(Collectors.toList());
validateUpperCaseTransform(allUppercase);
}
@Test
public void map_filter_count() {
long maryCount = lowerCaseStrings.stream().map(String::toUpperCase).filter(e -> e.equalsIgnoreCase("MARY"))
.count();
assertEquals(1, maryCount);
}
@Test
public void map_foreach() {
lowerCaseStrings.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
}
@Test
public void map_toArray() {
Object[] upperArr = lowerCaseStrings.stream().map(String::toUpperCase).toArray();
assertEquals("MARY", upperArr[0]);
assertEquals("SOMETHING", upperArr[1]);
assertEquals("END", upperArr[2]);
}
}
Output of mvn test -Dtest=StreamMap_TerminalOperationTest
------------------------------------------------------- T E S T S ------------------------------------------------------- Running jcg.zheng.demo.stream.StreamMap_TerminalOperationTest MARY SOMETHING END Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.176 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
5. Java Stream Map – Summary
In this example, I demonstrated how to use the Stream.map method via a lambda expression, function, and method reference shorthand. I also demonstrated how to chain the map method to intermediate operations and a terminal operation.
As you seen in these example, Stream.map provides a declarative way to transform the collection element without explicitly using a loop.
6. Download the Source Code
This example consists of a Maven project which contains several Junit tests to demonstrate the usage of Stream.map method.
You can download the full source code of this example here: Java Stream Map Example


Hey Mary Zheng, thank you for such an informative post on Java Stream Map. It’s been really helpful for me to understand the concept in detail.
Thanks. glad to hear it:)
I was looking for java stream map and I got exactly what I wanted. Thank you Mary Zheng
Thank you for post on Java Stream Map. It completes all details what I needed.