java grouping_java – 使用Collectors.groupingBy创建复杂对象

在oracle’s reduction tutorial中,可以使用Stream.collect计算流中的平均年龄:

Averager averageCollect = roster.stream()

.filter(p -> p.getGender() == Person.Sex.MALE)

.map(Person::getAge)

.collect(Averager::new, Averager::accept, Averager::combine);

但是如果想要创建Map< Person.Sex,Averager>使用lambda groupingBy,而不是简单的平均值,如教程结尾所示:

Map totalAgeByGender =

roster

.stream()

.collect(

Collectors.groupingBy(

Person::getGender,

Collectors.reducing(

0,

Person::getAge,

Integer::sum)));

解决方法:

是的,这有点微妙.要更改映射中的值,您必须更改groupingBy调用的下游收集器.在这种情况下,您必须应用嵌套的下游收集器.

流开始于人,我们希望Averagers作为地图的值.要从Person到Averager,我们首先需要将每个Person映射到它们的年龄(一个int),然后将整数提供给Averager.

我们首先对性别进行分组,因此需要处理与每个性别相对应的人员.下一步是使用映射收集器作为groupingBy的下游收集器将人员映射到他们的年龄.

现在你有了年龄,你想为每个组创建Averager实例.本教程中的Averager类已经有了收集器方法 – 它支持供应商,累加器和组合器函数,这些函数适合传递给前面示例中的Stream.collect调用.但是,我们希望使用Averager方法为我们刚刚建立的映射收集器构建嵌套的下游收集器,而不是Stream.collect.给定这些方法,创建收集器的便捷方法是使用Collector.of.

你可能会尝试这样的事情:

Map map =

roster.stream()

.collect(groupingBy(Person::getGender,

mapping(Person::getAge,

Collector.of(Averager::new, Averager::accept, Averager::combine))));

可是等等!这不起作用!你得到一个相当讨厌的编译失败,看起来像这样:

error: no suitable method found for of(Averager::new,Averager::accept,Averager::combine)

Collector.of(Averager::new, Averager::accept, Averager::combine))));

method Collector.of(Supplier,BiConsumer,BinaryOperator,Characteristics...) is not applicable

(cannot infer type-variable(s) T#1,R#1

(argument mismatch; bad return type in method reference

void cannot be converted to R#1))

method Collector.of(Supplier,BiConsumer,BinaryOperator,Function,Characteristics...) is not applicable

(cannot infer type-variable(s) T#2,A,R#2

(argument mismatch; bad return type in method reference

void cannot be converted to A))

where T#1,R#1,T#2,A,R#2 are type-variables:

T#1 extends Object declared in method of(Supplier,BiConsumer,BinaryOperator,Characteristics...)

R#1 extends Object declared in method of(Supplier,BiConsumer,BinaryOperator,Characteristics...)

T#2 extends Object declared in method of(Supplier,BiConsumer,BinaryOperator,Function,Characteristics...)

A extends Object declared in method of(Supplier,BiConsumer,BinaryOperator,Function,Characteristics...)

R#2 extends Object declared in method of(Supplier,BiConsumer,BinaryOperator,Function,Characteristics...)

确认!实际上,一旦你超越了20行错误信息的恐吓因素,冷静下来,并阅读它想说的内容,它实际上非常清楚编译器正在尝试做什么以及它是如何失败的.您还必须非常仔细地查看API.

本教程定义了在Stream.collect方法中使用的三种Averager方法,该方法具有以下签名(为简洁起见省略了泛型):

collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

注意,组合器方法是BiConsumer.但是,Collector.of方法定义如下:

of(Supplier supplier, BiConsumer accumulator, BinaryOperator combiner, Collector.Characteristics... characteristics)

(特征参数是varargs,它与我们无关,所以我们可以省略它.)

这里要注意的是Collector.of的组合器是BinaryOperator而不是BiConsumer. BinaryOperator版本与BiConsumer版本完全相同,但此外,它返回组合结果.要解决这个问题,我们只需更改combine()方法以返回Averager而不是void,然后我们添加一个返回此语句:

public Averager combine(Averager other) {

total += other.total;

count += other.count;

return this;

}

请注意,此版本的combine()方法仍适合作为第三个参数传递给Stream.collect. BinaryOperator兼容需要BiConsumer的地方;简单地忽略返回值.

一旦您对Averager.combine进行了此更改,此代码(与上面相同)应该有效:

Map map =

roster.stream()

.collect(groupingBy(Person::getGender,

mapping(Person::getAge,

Collector.of(Averager::new, Averager::accept, Averager::combine))));

标签:java,lambda,java-8,mapreduce

来源: https://codeday.me/bug/20190717/1491169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值