Collectors.averagingDouble()

Collectors.averagingDouble()

Java 8 流的新类 java.util.stream.Collectors 实现了 java.util.stream.Collector 接口,同时又提供了大量的方法对流 ( stream ) 的元素执行 map and reduce 操作,或者统计操作。

Collectors.averagingDouble() 方法将流中的所有元素视为 double 类型并计算他们的平均值。该方法返回的是同一个 Collectors 实例,因此可以进行链式操作。

Collectors.averagingDouble() 接受一个参数,这个参数是一个 lambda 表达式,用于对所有的元素执行一个 map 操作。

Java 所有集合的 stream().collect() 可以接受一个收集器实例作为其参数并返回该收集器的计算结果

例如下面的代码,collect() 方法会把所有的元素收集起来然后传递给 Collectors.averagingDouble(d->d*2) 收集器,对每个元素执行 *2 操作后计算平均值

@Test
public void AveragingDoubleExample() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    Double result = list.stream().map(s -> {
        System.out.println("map-> " + s);
        return s;
    }).collect(Collectors.averagingDouble(d -> {
                System.out.println(d + "-->" + d * 2);
                return d * 2;
            })
    );
    System.out.println(result);
}

运行结果: 结果显示计算平均值时为什么会打印两遍其中的值?

  • 如果在方法体中操作全局变量岂不是操作两遍?? 这不是坑么
  • 如果在方法体中做复杂操作,岂不是两倍??? 巨坑阿
  • 如果在方法体中做判断,判断后改动状态值,改两遍!!
  • ……
  • 用我智慧的大脑一想……没得玩了
map-> 1
1-->2
1-->2
map-> 2
2-->4
2-->4
map-> 3
3-->6
3-->6
map-> 4
4-->8
4-->8
5.0

为什么会这样打印两遍值?

  1. 详细对比了一下map,并打印相应的值

    1. 结论: 只打印一遍,说明流式操作只进行一次流式操作,排除map以及之前操作
  2. collect是一个收集器,收集传输过来的元素,并没有实际作用

    1. 联想Collectors.toList()推断出没有重复的值
    2. 观察源码发现,其实际上就是container而已
  3. 剩下的只有Collectors.averagingDouble了,那就直接进去看源码

    1. return new CollectorImpl<>(
                      () -> new double[4],
                      (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
                      (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
                      a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
                      CH_NOID);
      
    2. 可以看到两个mapper.applyAsDouble(t),其实这里就是调用我们的方法体,本质上都是对a进行赋值操作

      1. sumWithCompensation(a, mapper.applyAsDouble(t))操作的是a[0] a[1],后面操作的是 a[2], a[3]
      2. 暂时也是挺迷惑的,为什么不在一个方法中对a操作完……
      3. 如果有答案也希望指点一二
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`Collectors.groupingBy()`方法可以将流中的元素按照指定的条件分组,返回一个`Map`对象,其中键为分组条件,值为分组后的元素列表。而`Collectors.collectingAndThen()`方法可以对分组后的结果进行进一步的处理,例如对分组后的元素列表进行求和、求平均值等操作。 下面是一个示例代码,演示了如何使用`Collectors.groupingBy()`方法和`Collectors.collectingAndThen()`方法对一个`List`中的元素进行分组,并计算每个分组的平均值: ```java import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Employee> employees = Arrays.asList( new Employee("Alice", "IT", new BigDecimal("5000")), new Employee("Bob", "IT", new BigDecimal("6000")), new Employee("Charlie", "HR", new BigDecimal("7000")), new Employee("David", "HR", new BigDecimal("8000")) ); Map<String, Double> avgSalaryByDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDept, Collectors.collectingAndThen( Collectors.averagingDouble(e -> e.getSalary().doubleValue()), avg -> BigDecimal.valueOf(avg).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue() ) )); System.out.println(avgSalaryByDept); } } class Employee { private String name; private String dept; private BigDecimal salary; public Employee(String name, String dept, BigDecimal salary) { this.name = name; this.dept = dept; this.salary = salary; } public String getName() { return name; } public String getDept() { return dept; } public BigDecimal getSalary() { return salary; } } ``` 输出结果为: ``` {HR=7500.0, IT=5500.0} ``` 上述代码中,首先定义了一个`Employee`类,其中包含了员工的姓名、部门和薪水信息。然后创建了一个包含了4个`Employee`对象的`List`。接着使用`Collectors.groupingBy()`方法对`employees`流进行分组,按照部门进行分组,并将每个部门的员工薪水求平均值。最后使用`Collectors.collectingAndThen()`方法对平均值进行处理,保留2位小数并转换为`Double`类型。最终得到了一个`Map`对象,其中键为部门名称,值为该部门员工薪水的平均值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值