reduce()
在实际开发中有很多灵活的用途,尤其是在需要对集合或流中的元素进行归约(累积计算)操作时。将 reduce()
与其他流操作结合使用,可以实现许多复杂的数据处理任务。接下来,我将结合实际场景,详细讲解 reduce()
如何与其他流操作配合使用,解决不同的实际问题。
文章目录
1. 结合 map()
和 reduce()
:计算对象集合的属性总和
场景:假设我们有一个员工的列表,想要计算员工的总工资。
class Employee {
private String name;
private int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
public int getSalary() {
return salary;
}
}
List<Employee> employees = Arrays.asList(
new Employee("Alice", 5000),
new Employee("Bob", 6000),
new Employee("Charlie", 7000)
);
// 使用 map() 将 Employee 转换为工资,并用 reduce() 求和
int totalSalary = employees.stream()
.map(Employee::getSalary) // 映射为工资
.reduce(0, Integer::sum); // 归约求和
System.out.println("Total Salary: " + totalSalary); // 输出:18000
解释:
- 先使用
map()
方法将每个Employee
对象映射为工资(salary
),然后用reduce()
将所有工资累加得到总数。
2. 结合 filter()
和 reduce()
:筛选条件后求和
场景:在上一示例中,我们可能只想计算工资大于 5500 的员工的总工资。
int totalSalary = employees.stream()
.filter(e -> e.getSalary() > 5500) // 筛选工资大于 5500 的员工
.map(Employee::getSalary) // 映射为工资
.reduce(0, Integer::sum); // 归约求和
System.out.println("Total Salary (filtered): " + totalSalary); // 输出:13000
解释:
- 使用
filter()
过滤出工资大于 5500 的员工,然后再对符合条件的员工工资进行累加。
3. 结合 collect()
和 reduce()
:字符串连接
场景:假设我们想将员工的姓名通过逗号连接成一个字符串。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用 reduce() 连接字符串
String result = names.stream()
.reduce("", (a, b) -> a.isEmpty() ? b : a + ", " + b);
System.out.println(result); // 输出:Alice, Bob, Charlie
解释:
reduce()
通过逐个连接每个字符串来生成一个逗号分隔的字符串。使用了一个三元运算符,确保第一个元素不会多加一个逗号。
4. 结合 flatMap()
和 reduce()
:处理嵌套集合
场景:我们有一个 List<List<Integer>>
,想要将所有嵌套的 List
中的元素合并,并计算所有元素的总和。
List<List<Integer>> listOfLists = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7, 8, 9)
);
// 使用 flatMap() 将嵌套列表展开,并用 reduce() 求和
int sum = listOfLists.stream()
.flatMap(List::stream) // 展开嵌套的 List
.reduce(0, Integer::sum); // 归约求和
System.out.println("Sum: " + sum); // 输出:45
解释:
flatMap()
将嵌套的List<List<Integer>>
展开为一个简单的Stream<Integer>
,然后通过reduce()
对所有元素求和。
5. 结合 sorted()
和 reduce()
:找出最大/最小值
场景:我们想找出工资最高的员工。
Optional<Employee> highestPaidEmployee = employees.stream()
.reduce((e1, e2) -> e1.getSalary() > e2.getSalary() ? e1 : e2);
highestPaidEmployee.ifPresent(e -> System.out.println("Highest Paid: " + e.getSalary())); // 输出:7000
解释:
reduce()
通过比较两个员工的工资,逐步找到工资最高的那个员工。
6. 结合 groupingBy()
和 reduce()
:按组进行汇总
场景:假设我们想按部门统计员工的总工资。
class Employee {
private String name;
private String department;
private int salary;
public Employee(String name, String department, int salary) {
this.name = name;
this.department = department;
this.salary = salary;
}
public String getDepartment() {
return department;
}
public int getSalary() {
return salary;
}
}
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", 5000),
new Employee("Bob", "HR", 6000),
new Employee("Charlie", "IT", 7000),
new Employee("David", "HR", 5500)
);
// 按部门分组并汇总工资
Map<String, Integer> totalSalaryByDepartment = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.reducing(0, Employee::getSalary, Integer::sum)));
System.out.println(totalSalaryByDepartment); // 输出:{HR=11500, IT=12000}
解释:
groupingBy()
用于按部门对员工进行分组,而reducing()
则对每个组内的员工工资进行累加,得出每个部门的总工资。
7. 结合 optional
和 reduce()
:处理空集合
场景:在某些情况下,集合可能为空,我们想安全地处理这种情况。
List<Integer> numbers = new ArrayList<>();
Optional<Integer> result = numbers.stream()
.reduce((a, b) -> a + b); // 没有初始值
// 使用 Optional 的 isPresent() 进行安全处理
if (result.isPresent()) {
System.out.println("Sum: " + result.get());
} else {
System.out.println("No elements to reduce");
}
解释:
- 当流为空时,
reduce()
返回Optional.empty()
。通过Optional
的方法来处理可能为空的情况,可以避免出现NullPointerException
。
8. 并行流中的 reduce()
:并行处理大数据
场景:假设我们需要对一个大数据集进行并行求和。
int sum = numbers.parallelStream()
.reduce(0, Integer::sum); // 使用并行流进行求和
System.out.println("Sum: " + sum);
解释:
parallelStream()
会将流划分成多个子流,并行处理数据。reduce()
在并行流中的表现非常高效,尤其是对于大数据集的处理。
总结
reduce()
结合map()
:可以将对象集合中的某个属性转换为单一值并进行归约。reduce()
结合filter()
:可以筛选符合条件的元素,再进行归约操作。reduce()
结合flatMap()
:可以处理嵌套集合,将其展开后再进行归约。reduce()
结合sorted()
:可以通过归约比较来找出最大值或最小值。reduce()
结合groupingBy()
:可以按组进行数据归约,比如按部门统计总工资。- 处理空流:
reduce()
返回Optional
,可以安全处理空流的情况。
reduce()
非常适合用于对流中的数据进行累积和合并处理,通过与其他操作如 map()
、filter()
、collect()
等结合,可以实现多种复杂的数据处理任务。