In the tutorial Understand Java Stream API, you grasp the key concepts of the Java Stream API. You also saw some code examples illustrating some usages of stream operations, which are very useful for aggregate computations on collections such as filter, sum, average, sort, etc.

In this Java Stream tutorial, let’s look closer at these common aggregate functions in details.

Before begin, let’s see the data structure used in the examples. Given the following Personclass:

public class Person implements Comparable<Person> {
	private String firstName;
	private String lastName;
	private String email;
	private Gender gender;
	private int age;

	public Person() {
	}

	public Person(String firstName, String lastName,
				  String email, Gender gender, int age) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
		this.gender = gender;
		this.age = age;
	}

	// geters and setters go here...

	public int compareTo(Person another) {
		return this.age - another.getAge();
	}

	public String toString() {
		return this.firstName + " " + this.lastName;
	}
}
Note that the getters and setters are removed for brevity (you should implement them completely), and the natural ordering of this class is based on age of the person (see its compareTo() method). Also, the toString() method returns the name of the person in form of first name followed by last name, so printing a Person object will show its full name.

The gender property is an enum which is declared as follows:

public enum Gender { MALE, FEMALE }
The sample data is hardcoded as follows:

List<Person> listPersons = new ArrayList<>();

listPersons.add(new Person("Alice", "Brown", "alice@gmail.com", Gender.FEMALE, 26));
listPersons.add(new Person("Bob", "Young", "bob@gmail.com", Gender.MALE, 32));
listPersons.add(new Person("Carol", "Hill", "carol@gmail.com", Gender.FEMALE, 23));
listPersons.add(new Person("David", "Green", "david@gmail.com", Gender.MALE, 39));
listPersons.add(new Person("Eric", "Young", "eric@gmail.com", Gender.MALE, 26));
listPersons.add(new Person("Frank", "Thompson", "frank@gmail.com", Gender.MALE, 33));
listPersons.add(new Person("Gibb", "Brown", "gibb@gmail.com", Gender.MALE, 27));
listPersons.add(new Person("Henry", "Baker", "henry@gmail.com", Gender.MALE, 30));
listPersons.add(new Person("Isabell", "Hill", "isabell@gmail.com", Gender.FEMALE, 22));
listPersons.add(new Person("Jane", "Smith", "jane@gmail.com", Gender.FEMALE, 24));
Okay, let’s examine the aggregate functions that are intermediate operations first. For terminal operations, we simple use the forEach operation that print out the current element in the result stream.

 

1. Java Stream filter operation example

The filter() operation returns a new stream that consists elements matching a given condition which is typically a boolean test in form of a Lambda expression.



The following example lists only male persons:

listPersons.stream()
	.filter(p -> p.getGender().equals(Gender.MALE))
	.forEach(System.out::println);
Output:

Bob Young
David Green
Eric Young
Frank Thompson
Gibb Brown
Henry Baker
The following code shows only female who are under 25:

listPersons.stream()
	.filter(p -> p.getGender().equals(Gender.FEMALE) && p.getAge() <= 25)
	.forEach(System.out::println);
Result:

Carol Hill
Isabell Hill
Jane Smith
 

2. Java Stream map operation example

The map operation returns a new stream consisting of elements which are the results of applying a given function to the elements of the current stream. For example, converting a stream of Objects to a stream of String or a stream of primitive numbers.

The Stream API provides 4 methods for the map operation:

  • map(): transforms a stream of objects of type T to a stream of objects of type R.
  • mapToInt(): transforms a stream of objects to a stream of int primitives.
  • mapToLong(): transforms a stream of objects to a stream of long primitives.
  • mapToDouble(): transforms a stream of objects to a stream of double primitives.
The following code maps each person to his/her respective email address:

listPersons.stream()
	.map(p -> p.getEmail())
	.forEach(System.out::println);
Output:

alice@gmail.com
bob@gmail.com
carol@gmail.com
david@gmail.com
eric@gmail.com
frank@gmail.com
gibb@gmail.com
henry@gmail.com
isabell@gmail.com
jane@gmail.com
The following example maps each person to his/her age:

listPersons.stream()
	.mapToInt(p -> p.getAge())
	.forEach(age -> System.out.print(age + " - "));
Output:

26 - 32 - 23 - 39 - 26 - 33 - 27 - 30 - 22 - 24 -
The following example maps each person to his/her first name in uppercase:

listPersons.stream()
	.map(p -> p.getFirstName().toUpperCase())
	.forEach(System.out::println);
Output:

ALICE
BOB
CAROL
DAVID
ERIC
FRANK
GIBB
HENRY
ISABELL
JANE
 

3. Java Stream sorted operation example

The Stream API provides two overloads of the sorted operation that returns a new stream consisting elements sorted according to natural order or by a specified comparator:

  • sorted(): sorts by natural order
  • sorted(comparator): sorts by a comparator
The following example returns a stream of persons who are sorted by their age into ascending order:

listPersons.stream()
	.sorted()
	.forEach(p -> System.out.println(p + " - " + p.getAge()));
Look at the compareTo() method in the Person class, we see that the natural ordering is based on age:

public int compareTo(Person another) {
	return this.age - another.getAge();
}
Output of the above code:

Isabell Hill - 22
Carol Hill - 23
Jane Smith - 24
Alice Brown - 26
Eric Young - 26
Gibb Brown - 27
Henry Baker - 30
Bob Young - 32
Frank Thompson - 33
David Green - 39
The following code shows how to use a specified comparator to return a stream of persons who are sorted by their last name:

listPersons.stream()
	.sorted((p1, p2) -> p1.getLastName().compareTo(p2.getLastName()))
	.forEach(System.out::println);
Output:

Henry Baker
Alice Brown
Gibb Brown
David Green
Carol Hill
Isabell Hill
Jane Smith
Frank Thompson
Bob Young
Eric Young
 

4. Java Stream distinct operation example

The distinct() operation returns a stream consisting of the distinct elements (no duplicates) by comparing objects via their equals() method.

The following example returns a stream of distinct numbers from an array source:

int[] numbers = {23, 58, 12, 23, 17, 29, 99, 98, 29, 12};
Arrays.stream(numbers).distinct().forEach(i -> System.out.print(i + " "));
Output:

23 58 12 17 29 99 98
Combining with the map and sorted operations, the following example shows distinct last names of the persons in the above list, and sorts them by alphabetic order:

listPersons.stream()
	.map(p -> p.getLastName())
	.distinct()
	.sorted()
	.forEach(System.out::println);
Output:

Baker
Brown
Green
Hill
Smith
Thompson
Young
 

5. Java Stream limit operation example

The limit() operation returns a stream containing only a specified number of elements. Combining with the sorted() operation, the following example shows top 5 youngest persons:

listPersons.stream()
	.sorted()
	.limit(5)
	.forEach(System.out::println);
Output:

Isabell Hill
Carol Hill
Jane Smith
Alice Brown
Eric Young
 

6. Java Stream skip operation

The skip() operation returns a stream containing the remaining elements after discarding the first n elements of the stream.

Combining with the sorted and map operations, the following example finds the oldest age of the persons above:

System.out.print("The oldest age: ");
listPersons.stream()
	.sorted()
	.map(p -> p.getAge())
	.skip(listPersons.size() - 1)
	.forEach(System.out::println);
Output:

The oldest age: 39
As you can see, we can combine (chain) some aggregate functions together to achieve desired results. Such chaining is very common with streams operations. That makes streams powerful and flexible. I bet you will definitely love using it. I recommend you to read Java 8 in Action to master Streams programming in Java.

 

References:

 

Related Java Stream Tutorials

 

Other Java Collections Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (JavaStreamAggregateFunctionsExamples.zip)JavaStreamAggregateFunctionsExamples.zip[Java Stream Aggregate Functions Example]1 kB

Add comment

   


Comments 

#2Oshan2020-07-06 22:28
Thanks for sharing your knowledge with us!
Quote
#1Helena2017-03-03 12:20
Hello there!

Great post! It helped me a lot! Thank you!
But it would be cool to also see some examples of flatMap() operation, which flattens a normal map() operation
Quote