Java Stream API

Photo by Jeffrey Wegrzyn on Unsplash

Stream API is data flows from one side to other side.

Stream API is introduced in Java 8 in order to bring functional programming into Java.

What Stream API is

  • It is a data pipeline.
  • It use to process collection of objects or arrays.
  • It will not changed the original source.
  • It is efficient in coding.

In Stream API there are basically three major components as follows.

  • Source — Stream source can be any type of collection, array etc.
  • Intermediate Operations — In this, the incoming data stream will be converted according to the intermediate operation. Some intermediate operations are sort, map, filter.
  • Terminal Operations — This is the final operation of the stream. It will either return void, a single value or a collection. Some terminal operations are forEach, reduce, collect, min, sum, max, average.

Why it is easy to use?

Let’s do an example and figure it out. We need to print female student names whose gpa is greater than 3.6.

  • Student.java
public class Student {
private String name;
private int age;
private Gender gender;
private double gpa;

public Student(String name, int age, Gender gender, double gpa){
this.name = name;
this.age = age;
this.gender = gender;
this.gpa = gpa;
}

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

public Gender getGender() { return gender; }

public void setGender(Gender gender) { this.gender = gender; }

public double getGpa() { return gpa; }

public void setGpa(double gpa) { this.gpa = gpa; }
}
  • Gender.java
public enum Gender {
MALE,
FEMALE
}
  • Stream.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Stream {

public static void main(String[] args) {
Student student1 = new Student("Yashod", 25, Gender.MALE, 3.3);
Student student2 = new Student("Shawn", 26, Gender.MALE, 3.6);
Student student3 = new Student("Hasini", 26, Gender.FEMALE,
3.7);
Student student4 = new Student("Chamindika", 24, Gender.FEMALE,
3.5);
Student student5 = new Student("Udayanga", 25, Gender.MALE,
3.4);

List<Student> studentList = Arrays.asList(student1, student2,
student3, student4,
student5);

List<Student> femaleList = new ArrayList<>();

for (Student student: studentList) {
if (student.getGender() == Gender.FEMALE
&& student.getGpa() > 3.6) {
femaleList.add(student);
}
}

for (Student student: femaleList) {
System.out.println(student.getName());
}

}
}

Let’s do this using Stream API.

import java.util.Arrays;
import java.util.List;

public class Stream {

public static void main(String[] args) {
Student student1 = new Student("Yashod", 25, Gender.MALE, 3.3);
Student student2 = new Student("Shawn", 26, Gender.MALE, 3.6);
Student student3 = new Student("Hasini", 26, Gender.FEMALE,
3.7);
Student student4 = new Student("Chamindika", 24, Gender.FEMALE,
3.5);
Student student5 = new Student("Udayanga", 25, Gender.MALE,
3.4);

List<Student> studentList = Arrays.asList(student1, student2,
student3, student4,
student5);
studentList.stream()
.filter(x->x.getGender() == Gender.FEMALE)
.forEach(x -> System.out.println(x.getName()));

}
}

Wow that is easy. Yes it is Let’s explore the operations in Stream API.

Operations in Stream API

First let’s start with how to make a stream. There are several method of doing this.

  • For Collections collectionIdentifier.stream()
List<String> names = Arrays.asList("Yashod", "Shawn", "Hasini");
names.stream().forEach(System.out::println);
  • For Arrays Arrays.stream(arrayName)
int[] numbers = {1, 2, 3, 4, 5, 6, 7};
Arrays.stream(numbers).forEach(System.out::println);

Note: System.out::println is same as x -> System.out.println(x) .

Then we will move to some intermediate operations.

Sorted operation

This is used to sort the input stream. It will either sort in alphabetical order or it can be sorted using attribute.

  • Primitive types
int[] numbers = {4, 2, 6, 8, 10, 12};
Arrays.stream(numbers).sorted().forEach(x -> System.out.println(x));
  • Sorted with specific attribute in an object — Following will order the students according to the age of the students.
studentList.stream()
.sorted(Comparator.comparing(Student::getAge))
.forEach(System.out::println);
  • Sorted with more than one attribute in an object — Following first sort by the age and then sort by the gpa.
studentList.stream()
.sorted(Comparator.comparing(Student::getAge)
.thenComparing(Student::getGpa))

.forEach(System.out::println);

Filter Operation

In Filter operation input stream will filter using a condition and pass the filtered values forward.Stream.filter(x -> condition) .

  • Primitive type — This will filter the number greater than 3.
Arrays.stream(numbers)
.filter(x -> x > 3)
.forEach(x -> System.out.println(x));
  • Filter with single attribute of an Object— This will filter students whose age is greater than 24.
studentList.stream()
.filter(x -> x.getAge() > 24)
.forEach(System.out::println);
  • Filter with multiple attributes of an Object — This will filter students whose age is greater than 24 and GPA is higher than 3.5.
studentList.stream()
.filter(x -> x.getAge() > 24 && x.getGpa() > 3.5)
.forEach(System.out::println);

Map Operation

Map Operation is used to update or alter the input stream and output altered stream. map(inputValue -> outputValue)

  • Primitive Type — This will convert the input numbers to its squares.
Arrays.stream(numbers)
.map(x -> x * x)
.forEach(x -> System.out.println(x));
  • Map through the objects — Increment the age of the Student by one.
studentList.stream()
.map(x -> {
x.setAge(x.getAge() + 1);
return x;
})

.forEach(System.out::println);

Above map function will get the input object one by one and increase the age by one and return the object to the next operation.

Other intermediate operations

There are lots of intermediate operations and you can find when you need some are listed below.

  • findFirst()
  • skip()
  • peek()
  • flatMap()
  • distinct()

Then We will move to terminal operations.

ForEach operation

This is one of a popular terminal operation which returns void. It is commonly used for printing.

Arrays.stream(numbers)
.forEach(x -> System.out.println(x));

Collect operation

This will return a Collection. We can get a List, Map etc as we need and we will dive into most needed use cases of this operation.

  • Get a list
List<String> filteredNames = Arrays.stream(names)
.filter(x->x.startsWith("S"))
.collect(Collectors.toList());
  • Get a Map

For a map we need to provide to lambda functions one is for the key and other is for the value.

Map<String, Integer> mapped 
= studentList.stream()
.filter(x -> x.getAge() > 25)
.collect(Collectors.toMap(
x->x.getName(),
x->x.getAge()
));

for (String key: mapped.keySet()) {
System.out.println("Name :" + key + " and Age:"
+ mapped.get(key));
}
  • Group by an using a key
Map<Integer, List<Student>> groupMap 
= studentList.stream()
.filter(x -> x.getAge() > 25)
.collect(Collectors.groupingBy(
Student::getAge
));

for (Integer key: groupMap.keySet()) {
System.out.println("For Age :" + key);
for (Student student: groupMap.get(key)) {
System.out.println("Name :" + student.getName());
}
System.out.println("------------");
}

Above will group the Students using their age.

Reduce Operation

Reduce Operation will summarise the elements as we command as follows and reduce is having initial value, updated value holder and incoming value. Reduce function will return exactly one value.

reduce(initialvalue, (updatedValue, IncomingValue) -> operation);

Following is some example to add square of elements using reduce function.

int sumOfSquares 
= Arrays.stream(numbers).reduce(0, (int a, int b) -> a + b * b);

Other terminal operations

There are lots of intermediate operations and you can find when you need some are listed below.

  • sum()
  • min()
  • max()
  • average()
  • summaryStatistics()

The Code can be find in following Repo

Hopefully this is helpful.

If you have found this helpful please hit that 👏 and share it on social media :).

--

--

--

Technical Writer | Tech Enthusiast | Open source contributor

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

End-to-end payments for iGaming operators via Citizen’s PayBlox

Solved — Error while finding module specification for ‘pip’ (AttributeError: module ‘__main__’ has…

CS373 Fall 2021: Nandakishore(Nandu) Vudumula

MAJOR UPDATE: Game Dev. Progress, Core Tech Team, Website, and Roadmap

Upgrade to the next-gen Microsoft Windows Server 2016

Static Code Analysis for Unity3D — Part 2

Your business will suck until you apply this!

How to build a low-code app without the need for extensive training

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Yashod Perera

Yashod Perera

Technical Writer | Tech Enthusiast | Open source contributor

More from Medium

Annotations In Java

Setting Up Java

Coding Standards in Java

Java Date Time API’s