Java 8 introduced the java.util.stream.Collectors
class, which provides a collection of utility methods for performing mutable reduction operations on elements of a stream. This feature enables developers to process and manipulate data streams in a functional and readable way. The Collectors
class is a key part of the Stream API and offers various methods to collect data in different forms, such as List
, Set
, Map
, or even custom containers.
This article will dive into the practical uses of Collectors
with examples.
What is a Collector?
A Collector is an interface in the Stream API that acts as a bridge between a stream and its final result. It transforms elements of a stream into a desired data structure or performs operations like grouping, partitioning, and joining.
The Collectors
utility class provides several pre-built implementations of the Collector
interface to simplify common tasks.
Commonly Used Methods in Collectors Class
- toList(): Converts elements in the stream into a
List
. - toSet(): Converts elements in the stream into a
Set
. - toMap(): Converts elements in the stream into a
Map
. - groupingBy(): Groups elements by a classifier function.
- partitioningBy(): Partitions elements into two groups based on a predicate.
- joining(): Concatenates elements into a single
String
. - summarizingInt/Double/Long(): Generates summary statistics for numeric data.
- reducing(): Performs a custom reduction operation.
Example Use Cases
1. Collecting to a List
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Alice");
// Collecting names into a List
List<String> nameList = names.stream()
.collect(Collectors.toList());
System.out.println(nameList); // Output: [Alice, Bob, Charlie, Alice]
}
}
2. Grouping by a Property
import java.util.*;
import java.util.stream.Collectors;
class Employee {
String name;
String department;
Employee(String name, String department) {
this.name = name;
this.department = department;
}
}
public class CollectorExample {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "HR"),
new Employee("Bob", "Finance"),
new Employee("Charlie", "HR"),
new Employee("David", "IT")
);
// Group employees by department
Map<String, List<Employee>> employeesByDept = employees.stream()
.collect(Collectors.groupingBy(e -> e.department));
employeesByDept.forEach((dept, empList) -> {
System.out.println(dept + ": " + empList.stream()
.map(emp -> emp.name)
.collect(Collectors.joining(", ")));
});
// Output:
// HR: Alice, Charlie
// Finance: Bob
// IT: David
}
}
3. Partitioning by a Condition
public class CollectorExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
// Partition numbers into even and odd
Map<Boolean, List<Integer>> partitioned = numbers.stream()
.collect(Collectors.partitioningBy(num -> num % 2 == 0));
System.out.println("Even Numbers: " + partitioned.get(true)); // [2, 4, 6, 8]
System.out.println("Odd Numbers: " + partitioned.get(false)); // [1, 3, 5, 7]
}
}
4. Summarizing Data
import java.util.IntSummaryStatistics;
import java.util.Arrays;
public class CollectorExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 5, 7, 9, 11);
// Get summary statistics
IntSummaryStatistics stats = numbers.stream()
.collect(Collectors.summarizingInt(num -> num));
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
System.out.println("Average: " + stats.getAverage());
}
}
5. Custom Reduction
import java.util.Arrays;
import java.util.Optional;
public class CollectorExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Custom reduction to calculate product
Optional<Integer> product = numbers.stream()
.collect(Collectors.reducing((a, b) -> a * b));
System.out.println(product.orElse(0)); // Output: 120
}
}
Conclusion
The Collectors
class in Java 8 is a treasure trove for developers working with streams. It simplifies complex data processing tasks, turning potentially verbose code into clean and expressive one-liners. From grouping and partitioning to summarizing and custom reduction, the possibilities with Collectors
are vast.