造一个需求,有一批数据,需要某个字段进行分组,分组后对每组的值求平均(当然可以是任何操作)。
为了便于说明,用Json描述数据结构。
[
{
"name": "John",
"sex": "male",
"age": 34
},
{
"name": "Tom",
"sex": "male",
"age": 27
}, {
"name": "Simon",
"sex": "female",
"age": 33
},
{
"name": "Nancy",
"sex": "female",
"age": 36
},
{
"name": "Jackson",
"sex": "male",
"age": 44
},
{
"name": "Jone",
"sex": "male",
"age": 25
},
{
"name": "Rolin",
"sex": "female",
"age": 41
}
]
对于上面的数据,首先根据sex进行分组,然后求出男女平均年龄。
{
"mele": 33,
"female": 31
}
用到的实体类和工具类,对于getter/setter方法就省略了。
class User {
private String name;
private String sex;
private Integer age;
}
final class UserUtils {
public static Integer(List<User> users) {
int count = 0;
for (User user: users) {
count += user.getAge();
}
return users.isEmpty() ? 0 : count / users.size();
}
}
处理方式如下。
users.stream()
.collect(Collectors.groupingBy(User::getSex))
.entrySet()
.stream()
.map(UserUtils::avgSex)
.map(Map::entrySet)
.flatMap(Set::stream)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
上面这段刚开始写的时候,对于Stream不是很熟练,导致绕了路,改写如下。
users.stream()
.collect(Collectors.groupingBy(User::getSex))
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, UserUtils::avgSex));
另外此写法,如果遇到Key相同便会抛出异常。可以再添加一个合并Function。
users.stream()
.collect(Collectors.groupingBy(User::getSex))
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, UserUtils::avgSex), (a ,b) -> a);
这段代码的意思是,如果遇到Key相同的,保留原来的。
如果想用新的替代旧的,可以改写为(a, b) -> b
。
尽管Java已经到了17,但是8的很多特性也没有被发掘完。也难怪大家升级JDK的欲望如此低。