Java Stream Tutorial with Examples
1. Stream
Java 8 introduces a new concept called Stream. The first time you read about the Stream API, you may be confused because its name is similar to InputStream and OutputStream. But Java 8 Stream is something completely different. Stream is monad, therefore it plays an important role in bringing functional programming into Java.
Before starting this article, I recommend you to learn about functional interfaces and some common functional interfaces such as: Supplier, Consumer, Predicate. Here are my articles:
In functional programming, a monad is a structure that represents a computation that requires a sequence of steps linked together. For simplicity, see the monad example below:
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream() // (1) return a Stream
.filter(s -> s.startsWith("c")) // (2) return a new Stream
.map(String::toUpperCase) // (3) return a new Stream
.sorted() // (4) return a new Stream
.forEach(System.out::println); // (5)
Output:
C1
C2
- Create a Stream from a List object.
- Create a new Stream from the previous Stream and include only elements beginning with the letter "c".
- Create a new Stream from previous Stream with all elements converted to uppercase.
- Create a new Stream from the previous Stream by sorting the elements.
- Print out the elements of the last Stream.
In the previous example, steps (2) to (4) are intermediate operations because they return a Stream object. So you can call another method of Stream without having to end it with a semicolon.
A terminal operation is a method that returns void or returns a different type from Stream. In the previous example, step 5 is a terminal operation because Stream.forEach method returns void.
Here are the characteristics and advantages of Java 8 Stream:
- No storage. A Stream is not a data structure, but only a view of a data source (Which can be an array, a list or an I/O Channel,..).
- A Stream is functional in nature. Any modifications to a Stream will not change the data sources. For example, filtering a Stream will not delete any elements, but create a new Stream that includes the filtered elements.
- Lazy execution. Operations on a Stream will not be executed immediately. They will be executed only when users really need results.
- Consumable. The elements of a Stream are only visited once during the life of a Stream. Once traversed, a Stream is invalidated, just like an Iterator. You have to regenerate a new Stream if you want to traverse the Stream again.
See the illustration below to understand more how Stream works.
- Create a Stream from a collection.
- Filter colors other than red.
- Paint pink for the triangles.
- Filter shapes that are not square.
- Calculate the total area.
Employee class participates in a few examples in this article:
Employee.java
package org.o7planning.stream.ex;
public class Employee {
private String name;
private float salary;
private String gender; // "M", "F"
public Employee(String name, float salary, String gender) {
this.name = name;
this.salary = salary;
this.gender = gender;
}
public String getName() {
return name;
}
public float getSalary() {
return salary;
}
public String getGender() {
return gender;
}
public boolean isFemale() {
return "F".equals(this.getGender());
}
}
2. Stream.filter(Predicate)
Returns a Stream consisting of the elements of this Stream that match the given Predicate.
Stream<T> filter(Predicate<? super T> predicate)
Example: From a list of employees (Employee), print out a list of female employees with salaries greater than 2500.
Stream_filter_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Stream_filter_ex1 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
// Employee is Female and salary > 2500
Predicate<Employee> predicate = e -> e.isFemale() && e.getSalary() > 2500;
employees //
.stream() //
.filter(predicate) //
.forEach(e -> System.out.println(e.getName()+ " : " + e.getSalary()));
}
}
Output:
Mary T. : 5000.0
Sophia B. : 7000.0
If a method is non-static (non-static method), has no parameters, and returns a boolean value, then its reference is considered a Predicate. (See explanation in my article about Java Predicate).
Example: Create a Predicate from a method reference:
Predicate<Employee> p = Employee::isFemale;
// Same as:
Predicate<Employee> p = employee -> employee.isFemale();
Stream_filter_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_filter_ex2 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.filter(Employee::isFemale) //
.forEach(e -> System.out.println(e.getName()+ " : " + e.getSalary()));
}
}
Output:
Sarah M. : 2000.0
Mary T. : 5000.0
Sophia B. : 7000.0
3. Stream.sorted(Comparator)
Returns a Stream consisting of the elements of this stream, sorted according to the provided Comparator.
Stream<T> sorted(Comparator<? super T> comparator)
- Java Comparator
Example: Sorting employees in ascending salary order:
Stream_sort_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_sort_ex1 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.sorted (
(e1,e2) -> (int) (e1.getSalary() - e2.getSalary())
) //
.forEach(e -> System.out.println(e.getSalary() + " : " + e.getName()));
}
}
Output:
1500.0 : John P.
1700.0 : Charles B.
2000.0 : Sarah M.
5000.0 : Mary T.
7000.0 : Sophia B.
Example: Sort the employee by gender and salary:
Stream_sort_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_sort_ex2 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() //
.sorted (
(e1,e2) -> {
int v = e1.getGender().compareTo(e2.getGender());
if(v == 0) {
v = (int) (e1.getSalary() - e2.getSalary());
}
return v;
}
) //
.forEach(e -> System.out.println(e.getGender()+ " : "+ e.getSalary() + " : " + e.getName()));
}
}
Output:
F : 2000.0 : Sarah M.
F : 5000.0 : Mary T.
F : 7000.0 : Sophia B.
M : 1500.0 : John P.
M : 1700.0 : Charles B.
4. Stream.map(Function)
Returns a new Stream consisting of the results of applying the given Function to the elements of this Stream.
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Example: Converts a list of String(s) to uppercase.
Stream_map_ex1.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Stream_map_ex1 {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
List<String> newList = list //
.stream() // a Stream
.map(s -> s.toUpperCase()) // a new Stream
.collect(Collectors.toList()); // Stream => List
System.out.println(list); // [a, b, c, d, e]
System.out.println(newList); // [A, B, C, D, E]
}
}
If a method is non-static (non-static method), no parameters, and returns a value, then its reference is considered as a Function. (See more explanation in my article about Java Function).
// Create a Function from a method reference:
Function<String, String> f1 = String::toUpperCase;
// Same as:
Function<String, String> f2 = s -> s.toUpperCase();
Stream_map_ex2.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Stream_map_ex2 {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
List<String> newList = list //
.stream() // a Stream
.map(String::toUpperCase) // a new Stream
.collect(Collectors.toList()); // Stream => List
System.out.println(list); // [a, b, c, d, e]
System.out.println(newList); // [A, B, C, D, E]
}
}
Example: Double salary for every employee in a list:
Stream_map_ex3.java
package org.o7planning.stream.ex;
import java.util.Arrays;
import java.util.List;
public class Stream_map_ex3 {
public static void main(String[] args) {
Employee john = new Employee("John P.", 1500, "M");
Employee sarah = new Employee("Sarah M.", 2000, "F");
Employee charles = new Employee("Charles B.", 1700, "M");
Employee mary = new Employee("Mary T.", 5000, "F");
Employee sophia = new Employee("Sophia B.", 7000, "F");
List<Employee> employees = Arrays.asList(john, sarah, charles, mary, sophia);
employees //
.stream() // a Stream.
.map((e) -> new Employee(e.getName(), e.getSalary()* 2, e.getGender())) // a new Stream.
.forEach(c -> System.out.println(c.getName()+ " : " + c.getSalary()));
}
}
Output:
John P. : 3000.0
Sarah M. : 4000.0
Charles B. : 3400.0
Mary T. : 10000.0
Sophia B. : 14000.0
Java Basic
- Customize java compiler processing your Annotation (Annotation Processing Tool)
- Java Programming for team using Eclipse and SVN
- Java WeakReference Tutorial with Examples
- Java PhantomReference Tutorial with Examples
- Java Compression and Decompression Tutorial with Examples
- Configuring Eclipse to use the JDK instead of JRE
- Java String.format() and printf() methods
- Syntax and new features in Java 8
- Java Regular Expressions Tutorial with Examples
- Java Multithreading Programming Tutorial with Examples
- JDBC Driver Libraries for different types of database in Java
- Java JDBC Tutorial with Examples
- Get the values of the columns automatically increment when Insert a record using JDBC
- Java Stream Tutorial with Examples
- Java Functional Interface Tutorial with Examples
- Introduction to the Raspberry Pi
- Java Predicate Tutorial with Examples
- Abstract class and Interface in Java
- Access modifiers in Java
- Java Enums Tutorial with Examples
- Java Annotations Tutorial with Examples
- Comparing and Sorting in Java
- Java String, StringBuffer and StringBuilder Tutorial with Examples
- Java Exception Handling Tutorial with Examples
- Java Generics Tutorial with Examples
- Manipulating files and directories in Java
- Java BiPredicate Tutorial with Examples
- Java Consumer Tutorial with Examples
- Java BiConsumer Tutorial with Examples
- What is needed to get started with Java?
- History of Java and the difference between Oracle JDK and OpenJDK
- Install Java on Windows
- Install Java on Ubuntu
- Install OpenJDK on Ubuntu
- Install Eclipse
- Install Eclipse on Ubuntu
- Quick Learning Java for beginners
- History of bits and bytes in computer science
- Data Types in java
- Bitwise Operations
- if else statement in java
- Switch Statement in Java
- Loops in Java
- Arrays in Java
- JDK Javadoc in CHM format
- Inheritance and polymorphism in Java
- Java Function Tutorial with Examples
- Java BiFunction Tutorial with Examples
- Example of Java encoding and decoding using Apache Base64
- Java Reflection Tutorial with Examples
- Java remote method invocation - Java RMI Tutorial with Examples
- Java Socket Programming Tutorial with Examples
- Which Platform Should You Choose for Developing Java Desktop Applications?
- Java Commons IO Tutorial with Examples
- Java Commons Email Tutorial with Examples
- Java Commons Logging Tutorial with Examples
- Understanding Java System.identityHashCode, Object.hashCode and Object.equals
- Java SoftReference Tutorial with Examples
- Java Supplier Tutorial with Examples
- Java Aspect Oriented Programming with AspectJ (AOP)
Show More
- Java Servlet/Jsp Tutorials
- Java Collections Framework Tutorials
- Java API for HTML & XML
- Java IO Tutorials
- Java Date Time Tutorials
- Spring Boot Tutorials
- Maven Tutorials
- Gradle Tutorials
- Java Web Services Tutorials
- Java SWT Tutorials
- JavaFX Tutorials
- Java Oracle ADF Tutorials
- Struts2 Framework Tutorials
- Spring Cloud Tutorials