玩转Java 8 Stream 系列二进阶(Collectors.mapping 、Collectors.reducing、Collectors.summarizingInt等)

前沿

这篇文章我们聊聊Stream的一些进阶的操作api,准备数据这些与上篇相同,这里就不阐述,如果不了解的,欢迎大家先看

玩转Java 8 Stream系列一

这篇文章还是通过对比的方式进行。

正文

查询以每个家庭为组内的成员名称集合

写法一

Map<Integer, List<String>> familyMap = new HashMap();
for (Member member : memberList) {
    //操作Member对象
    List<String> members = familyMap.get(member.getFamilyId());
    if (CollectionUtils.isEmpty(members)) {
        members = new ArrayList<>();
    }
    members.add(member.getMemberName());
    familyMap.put(member.getFamilyId(), members);
}

解析:遍历集合,根据familyId查询map,如果不存在,则实例化一个集合,将成员名字添加进去

写法二

familyMap = memberList.stream().collect(Collectors.groupingBy(Member::getFamilyId, Collectors.mapping(Member::getMemberName, Collectors.toList())));

解析:通过stream的写法,写法上无需判断集合以及创建集合,这里是先按照familyId进行分组(Collectors.groupingBy),再处理分组后List集合,使用Collectors.mapping方法,获取成员名称,最后再选择输出的形式,这里使用Collectors.toList(),最后输出Map<Integer, List<String>> 格式的数据。

查询每个家庭的收入总和

分析:先将数据以家庭ID分组后,在将分组后的成员积蓄累加,写法与上面的查询以每个家庭为组内的成员名称集合类似,只不过这里要对数据中totalMoney进行累加

写法一

Map<Integer, BigDecimal> familyMap = new HashMap();
for (Member member : memberList) {
    //操作Member对象
    BigDecimal bigDecimal = familyMap.get(member.getFamilyId());
    if (Objects.isNull(bigDecimal)) {
        bigDecimal = new BigDecimal(0);
    }
    bigDecimal= bigDecimal.add(member.getTotalMoney());
    familyMap.put(member.getFamilyId(), bigDecimal);
}

写法二

familyMap = collect(Collectors.groupingBy(Member::getFamilyId, Collectors.reducing(BigDecimal.ZERO, Member::getTotalMoney, BigDecimal::add)));

查询每个家庭的数量之和 

写法一

Map<Integer, Integer> familyMap = new HashMap();
for (Member member : memberList) {
    //操作Member对象
    Integer memberTotal = familyMap.get(member.getFamilyId());
    if (Objects.isNull(memberTotal)) {
        memberTotal = 0;
    }
    memberTotal += member.getMemberAmount();
    familyMap.put(member.getFamilyId(), memberTotal);
}

写法二

familyMap =  memberList.stream().collect(Collectors.groupingBy(Member::getFamilyId, Collectors.reducing(0, Member::getMemberAmount, Integer::sum)));

假如我们要统计每个家庭的数量之和、数量平均值、最大值、最小值,这些,那么使用写法会比较麻烦,要对 familyMap 集合再做比较

那么通过下面的写法可以避免这些问题

Map<Integer, IntSummaryStatistics> collect = memberList.stream().collect(Collectors.groupingBy(Member::getFamilyId, Collectors.summarizingInt(Member::getMemberAmount)));

生成一个value为 IntSummaryStatistics对象,如果我们想统计累加

Map<Integer, Long> collect2 = collect.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, k -> k.getValue().getSum()));

如果想统计最大值,只需要将 getSum方法修改成getMax,最小值修改成getMin ,求和 getCount

平均值getAverage 是不是比较方便

查询是否存在成员名称叫张山的人

 写法一

boolean isExist = false;
for (Member member : memberList) {
    //操作Member对象
    if ("张三".equals(member.getMemberName())){
        isExist = true;
        break;
    }
}
System.out.println(isExist);

写法二

Optional<Member> first = memberList.stream().filter(k -> "张三".equals(k.getMemberName())).findFirst();
System.out.println(first.isPresent());

如果找到第一个,那么就返回一个 Optional对象,调用isPresent方法,查看是否存在,而且返回的Optional对象还可以进行下一步操作,例如再次过滤,调用filter方法。

map与flatMap区别

例如通过map,我们获取成员名称,那么他会将成员名字作为一个整体返回,不会在细分,而flatMap会将成员名称再细分,假如成员名称叫张三-1,map会将张三-1作为一个整体来处理,flatMap则将张三-1会再次拆分处理,可能拆分成张、三、-、1这种。而在使用上的区别是flatMap的入参必须是Stream类型,而map则无需,例如下面代码

memberList.stream().flatMap(k -> Stream.of(k.getMemberName().split("-"))).collect(Collectors.toList()).forEach(System.out::println);

 flatMap入参是Stream类型,所以我们可以对memberName字段进行处理,例如上面是通过-来分割,将分割后的结果加入的Stream中,因为是Sream类型,所以还可以对结果进行其他的逻辑处理。

memberList.stream().map(Member::getMemberName).collect(Collectors.toList()).forEach(System.out::println);

map无需Steam类型,处理更加简单。

猜你喜欢

转载自blog.csdn.net/zanpengfei/article/details/125055745
今日推荐