In Java’s Stream API, Collectors.mapping is a collector that applies a mapping function to the input elements before collecting the results. It is often used as part of nested transformations, where one wants to apply a specific transformation on elements that are part of a more complex collector, such as a groupingBy.
Syntax of Collectors.mapping
Collectors.mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream)
mapper: A function to map elements.downstream: A collector to collect the mapped elements.
When to Use It:
Collectors.mapping is typically used when:
- You need to transform (or map) the elements of a collected result into a different form.
- You are combining it with other collectors, such as
Collectors.groupingBy,Collectors.toList, orCollectors.toSet.
Example of Using Collectors.mapping for Nested Transformation
Use Case: Group students by their grade and collect a list of their names in uppercase.
package org.kodejava.util.stream;
import java.util.*;
import java.util.stream.Collectors;
class Student {
String name;
String grade;
Student(String name, String grade) {
this.name = name;
this.grade = grade;
}
}
public class Main {
public static void main(String[] args) {
// Example student list
List<Student> students = Arrays.asList(
new Student("Alice", "A"),
new Student("Bob", "B"),
new Student("Charlie", "A"),
new Student("David", "B"),
new Student("Eva", "C")
);
// Group by grade and collect names in uppercase
Map<String, List<String>> studentsByGrade = students.stream()
.collect(Collectors.groupingBy(
student -> student.grade, // Key: grade
Collectors.mapping(
student -> student.name.toUpperCase(), // Transformation: uppercase name
Collectors.toList() // Downstream collector: collect into a list
)
));
// Output the result
studentsByGrade.forEach((grade, names) -> {
System.out.println("Grade: " + grade + ", Students: " + names);
});
}
}
Output:
Grade: A, Students: [ALICE, CHARLIE]
Grade: B, Students: [BOB, DAVID]
Grade: C, Students: [EVA]
Nested Transformation with Collectors.mapping
Collectors.mapping can also be used in more intricate scenarios. For instance:
Use Case: Group employees by department and collect a list of their projects’ names.
package org.kodejava.util.stream;
import java.util.*;
import java.util.stream.Collectors;
class Employee {
String name;
String department;
List<String> projects;
Employee(String name, String department, List<String> projects) {
this.name = name;
this.department = department;
this.projects = projects;
}
}
public class Main {
public static void main(String[] args) {
// List of employees
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", Arrays.asList("Project1", "Project2")),
new Employee("Bob", "HR", Arrays.asList("HRSystem")),
new Employee("Charlie", "IT", Arrays.asList("Project3")),
new Employee("David", "Finance", Arrays.asList("PayrollSystem"))
);
// Group employees by department and collect their project names
Map<String, List<String>> projectsByDepartment = employees.stream()
.collect(Collectors.groupingBy(
employee -> employee.department, // Key: department
Collectors.mapping(
employee -> String.join(", ", employee.projects), // Join multiple projects
Collectors.toList() // Collect projects into a list
)
));
// Output results
projectsByDepartment.forEach((dep, projects) -> {
System.out.println("Department: " + dep + ", Projects: " + projects);
});
}
}
Output:
Department: IT, Projects: [Project1, Project2, Project3]
Department: HR, Projects: [HRSystem]
Department: Finance, Projects: [PayrollSystem]
How Collectors.mapping Works in Nested Use Cases
In nested or hierarchical collections:
Collectors.mappingtransforms the input data.- The transformed data is passed to another collector, often as part of a
downstreamprocess likegroupingBy(for grouping) ortoMap(for key-value transformations).
Key Points to Remember:
Collectors.mappingis a middle step of transformation, often followed by an operation like collecting into aListorSet.- It is useful when transforming data within a complex stream operation.
- The nesting of collectors enables flexible and powerful data aggregation, suited for real-world use cases like categorizing, summarizing, and transforming collections.
