In Java 8, the introduction of the Stream
API brought a new functional programming style to the language. One of the most useful classes in this API is Collectors
, which provides a set of convenient reduction operations, allowing you to perform complex data operations in a concise and readable manner.
In this blog post, we’ll explore the Collectors
class and its various methods, complete with examples to help you understand and leverage its power.
Setting Up the Example
Before we dive into the methods, let’s define a simple Person
class that we’ll use for our examples:
class Person {
private String name;
private int age;
private double salary;
// Constructor, getters, and setters omitted for brevity
}
Now, let’s create a list of Person
objects that we’ll use throughout the examples:
List<Person> people = Arrays.asList(
new Person("Alice", 25, 50000),
new Person("Bob", 30, 60000),
new Person("Charlie", 35, 70000),
new Person("David", 40, 80000),
new Person("Eve", 45, 90000),
new Person("Alice", 27, 55000)
);
Exploring Collectors Methods
1. toList()
The toList()
method collects the stream elements into a new List
instance. Here’s an example that creates a list of names from the people
list:
List<String> names = people.stream()
.map(Person::getName)
.collect(Collectors.toList());
// names = [Alice, Bob, Charlie, David, Eve, Alice]
2. toSet()
The toSet()
method collects the stream elements into a new Set
instance, eliminating duplicates. Let’s use it to get a set of unique names:
Set<String> uniqueNames = people.stream()
.map(Person::getName)
.collect(Collectors.toSet());
// uniqueNames = [Alice, Bob, Charlie, David, Eve]
3. toMap()
The toMap()
method collects the stream elements into a Map
instance, where you can specify how to derive the keys and values. Here’s an example that creates a map of names to salaries:
Map<String, Double> namesToSalaries = people.stream()
.collect(Collectors.toMap(
Person::getName,
Person::getSalary
));
// namesToSalaries = {Alice=55000.0, Bob=60000.0, Charlie=70000.0, David=80000.0, Eve=90000.0}
4. groupingBy()
The groupingBy()
method groups the stream elements by a specified function. Let’s group people by their age:
Map<Integer, List<Person>> peopleByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
/*
peopleByAge = {
25=[Alice(25, 50000.0)],
30=[Bob(30, 60000.0)],
35=[Charlie(35, 70000.0)],
40=[David(40, 80000.0)],
45=[Eve(45, 90000.0)],
27=[Alice(27, 55000.0)]
}
*/
5. joining()
The joining()
method concatenates the string representations of the stream elements, optionally separated by a delimiter. Here’s an example that creates a comma-separated list of names:
String namesCommaSeparated = people.stream()
.map(Person::getName)
.collect(Collectors.joining(", "));
// namesCommaSeparated = "Alice, Bob, Charlie, David, Eve, Alice"
6. counting()
The counting()
method counts the number of elements in the stream. Let’s count the number of people in our list:
long peopleCount = people.stream()
.collect(Collectors.counting());
// peopleCount = 6
7. averagingInt()
, averagingLong()
, averagingDouble()
These methods calculate the average of the stream elements after applying the provided mapping function. Here’s an example that calculates the average age of people:
double averageAge = people.stream()
.collect(Collectors.averagingInt(Person::getAge));
// averageAge = 35.0
8. summarizingInt()
, summarizingLong()
, summarizingDouble()
These methods produce a SummaryStatistics
object that captures various summary data about the elements in the stream, such as count, sum, average, min, and max. Let’s calculate some summary statistics for salaries:
DoubleSummaryStatistics salarySummary = people.stream()
.collect(Collectors.summarizingDouble(Person::getSalary));
/*
salarySummary = {
count=6,
sum=350000.0,
min=50000.0,
average=58333.333333333336,
max=90000.0
}
*/
These are just a few examples of the powerful methods available in the Collectors
class. There are many more methods that can help you perform various data operations efficiently and concisely.
Conclusion
The Collectors
class in Java’s Stream
API provides a rich set of utility methods for performing common data processing tasks. By understanding and leveraging these methods, you can write more concise and expressive code, making your codebase more readable and maintainable.
In this blog post, we covered several essential methods from the Collectors
class, including toList()
, toSet()
, toMap()
, groupingBy()
, joining()
, counting()
, averagingInt()
, averagingLong()
, averagingDouble()
, summarizingInt()
, summarizingLong()
, and summarizingDouble()
. However, the Collectors
class offers many more methods to explore, so be sure to consult the official Java documentation for a comprehensive understanding of its capabilities.
Happy coding!