云计算百科
云计算领域专业知识百科平台

StreamAPI更复杂的收集器使用场景

更复杂的收集器使用场景通常涉及到多个收集器的组合、自定义收集器的创建以及处理复杂数据结构的需求。以下是一些更加复杂的收集器使用示例:

1. 多级分组

假设你有一个包含员工信息的列表,并希望先按部门分组,然后再按薪资水平(例如是否高于某个阈值)进一步分组。

Map<String, Map<Boolean, List<Employee>>> complexGrouping = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.partitioningBy(employee -> employee.getSalary() > 6500)));

在这个例子中,我们首先通过 groupingBy 按照部门进行分组,然后通过 partitioningBy 根据薪资是否高于某个阈值进一步细分。

2. 聚合统计与下游收集器结合

除了简单的计数外,还可以计算每个部门的平均工资、最高和最低工资等详细统计信息。

Map<String, DoubleSummaryStatistics> salaryStatsPerDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summarizingDouble(Employee::getSalary)));

salaryStatsPerDept.forEach((department, stats) ->
System.out.println(department + ": avg=" + stats.getAverage() + ", count=" + stats.getCount()));

这里,我们使用了 summarizingDouble 收集器来获取详细的统计信息,包括总和、平均值、最大值、最小值和元素数量。

3. 自定义收集器

有时内置的收集器可能不足以满足特定需求。这时可以通过实现自定义收集器来完成复杂任务。例如,假设我们需要创建一个将员工按照姓氏首字母分类,并计算每个类别下的平均薪资的映射:

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

public class CustomCollectorExample {

public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "HR", 5000),
new Employee("Bob", "IT", 7000),
new Employee("Charlie", "IT", 8000),
new Employee("David", "HR", 6000)
);

Map<Character, Double> result = employees.stream()
.collect(new InitialLetterSalaryAverager());

result.forEach((letter, avgSalary) ->
System.out.println(letter + ": " + avgSalary));
}

private static class InitialLetterSalaryAverager implements Collector<Employee, Map<Character, Tuple>, Map<Character, Double>> {

@Override
public Supplier<Map<Character, Tuple>> supplier() {
return HashMap::new;
}

@Override
public BiConsumer<Map<Character, Tuple>, Employee> accumulator() {
return (map, employee) -> {
char firstLetter = employee.getName().charAt(0);
map.computeIfAbsent(firstLetter, k -> new Tuple()).add(employee.getSalary());
};
}

@Override
public BinaryOperator<Map<Character, Tuple>> combiner() {
return (map1, map2) -> {
map2.forEach((key, value) -> map1.merge(key, value, Tuple::merge));
return map1;
};
}

@Override
public Function<Map<Character, Tuple>, Map<Character, Double>> finisher() {
return map -> map.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().average()));
}

@Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Characteristics.IDENTITY_FINISH);
}

private static class Tuple {
private int count = 0;
private double totalSalary = 0;

public void add(double salary) {
count++;
totalSalary += salary;
}

public Tuple merge(Tuple other) {
this.count += other.count;
this.totalSalary += other.totalSalary;
return this;
}

public double average() {
return totalSalary / count;
}
}
}
}

这个自定义收集器实现了 Collector 接口,它根据员工名字的第一个字母对他们进行分组,并计算每个字母开头的名字对应的平均薪资。这种方法虽然比直接使用内置收集器复杂得多,但它展示了如何在 Java 中灵活地定制流的行为以适应具体的需求。

4. 链式收集器

有时候需要对数据进行多层次的汇总。例如,你可能想要先按部门分组,然后对每个部门内的员工进行一些其他的统计分析(如计算每个部门内所有员工的工资总和)。

Map<String, Integer> totalSalaryPerDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));

这会给你一个 Map<String, Integer>,其中键是部门名称,值是该部门所有员工的工资总和。

通过这些高级用法,你可以充分利用 Stream API 的灵活性来处理各种复杂的数据转换和聚合任务。无论是多级分组、详细统计分析还是创建自定义收集器,都能帮助你编写出简洁而强大的代码。

赞(0)
未经允许不得转载:网硕互联帮助中心 » StreamAPI更复杂的收集器使用场景
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!