Java8 Stream非官方教程|第五篇:Collectors收集器

1.收集器简介

先看一个收集器的例子
在一个user列表中,用年龄进行分组
1.8之前的写法

 Map<Integer, List<User>> mapNew = new HashMap<>();
        for (int i = 0; i < listUser.size(); i++) {
            User user = listUser.get(i);
            int age = user.getAge();
            List<User> users = mapNew.get(age);
            if (null != users && users.size() > 0) {
                break;
            }
            List<User> listUserIn = new ArrayList<>();
            for (User userIn : listUser) {
                if (userIn.getAge() == age) {
                    listUserIn.add(userIn);
                }
            }
            mapNew.put(age, listUserIn);
        }
        log.info(mapNew.toString());

jdk1.8 stream 一行代码就完成了上面的功能

 Map<Integer, List<User>> collect = listUser.stream().collect(groupingBy(User::getAge));
 log.info(collect.toString());

从这个例子就能看出来,函数式编程的优势,我们只需要关心生成的结果,而不需要关注过程;在这个例子中,传递在collect方法参数的是Collector接口的一个实现,也就是给Stream元素做分组汇总的方法groupingBy,和sql很像。
收集器可以更加简洁而灵活的定义,Collectors类中实现了很多收集器,配合collect()使用,collect方法将对流的元素触发一个规约操作生成结果。

2.Collectors三大功能

先初始化一个user集合

@Slf4j
public class ModeCollectors {

    List<User> listUser = new ArrayList<>();

    @Before
    public void initList() {
        listUser = this.getListUsers();
    }

    private List<User> getListUsers() {
        List<User> listUser = new ArrayList<User>();
        for (int i = 0; i < 10; i++) {
            listUser.add(new User("man" + i, i, "男"));
        }

        for (int i = 0; i < 10; i++) {
            listUser.add(new User("woman" + i, i, "女"));
        }
        return listUser;
    }
  }
import lombok.Data;

@Data
public class User implements Comparable<User> {
    private String name;
    private Integer age;
    private String sex;

    public User(String name, Integer age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }


    @Override
    public int compareTo(User o) {
        int i = -(this.getAge() - o.getAge());
        if (i == 0) {
            return -(this.age - o.getAge());
        }
        return i;
    }

    public boolean isMan(){
        return sex.equals("男");
    }
}

2.1将流元素归约和汇总成一个值

2.1.1 counting

   /**
     * counting 
     * 对所有的女生进行数量统计
     */
    @Test
    public void testCount() {
        Long wo = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(counting());
        log.info(String.valueOf(wo));
    }

执行结果
在这里插入图片描述

2.1.2 summingInt

   /**
     * summingInt求和
     */
    @Test
    public void testSum() {
        //找到所有女生 并求年龄之和
        Integer collect = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(summingInt(User::getAge));
        log.info(String.valueOf(collect));
    }

执行结果
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a9f43816b43574d2bb8d0f8097c98012.png

2.1.3 averagingInt

 /**
     * averagingInt 平均数
     */
    @Test
    public void testAverag() {
        Double collect = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(averagingInt(User::getAge));
        log.info(String.valueOf(collect));
    }

执行结果
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a9f43816b43574d2bb8d0f8097c98012.png

2.1.4 maxBy

  /**
     * 最大值
     */
    @Test
    public void testMax() {
        Comparator<User> userAgeComparable = comparingInt(User::getAge);
        Optional<User> wo = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(maxBy(userAgeComparable));
        log.info(String.valueOf(wo.get()));
    }

2.1.5 minBy

   /**
     * 最小值
     */
    @Test
    public void testMin() {
        Comparator<User> userAgeComparable = comparingInt(User::getAge);
        Optional<User> wo = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(minBy(userAgeComparable));
        log.info(String.valueOf(wo.get()));
    }

2.1.6 summary(综合)

这个收集器是上面所有功能的综合,使用对应的方法可以获取所有的值

    /**
     * summary 综合
     */
    @Test
    public void testSummary() {
        IntSummaryStatistics wo = listUser.stream().filter(user -> user.getName().substring(0, 2).equals("wo")).collect(summarizingInt(User::getAge));
        log.info(String.valueOf(wo.toString()));
        wo.getAverage();
        wo.getCount();
        wo.getMax();
        wo.getMin();
        wo.getSum();
    }

执行结果
在这里插入图片描述

2.1.7 joining

将字符串连接在一起,这个比较实用

    /**
     * joining 连接字符串
     */
    @Test
    public void testJoin() {
        String wo = listUser.stream()
                .filter(user -> user.getName().substring(0, 2).equals("wo"))
                .map(User::getName)
                .collect(joining(","));
        log.info(wo);
    }

执行结果
在这里插入图片描述

2.1.8 reducing

Reducing 这一块的内容和之前的文章比较像Java Stream非官方教程|第四篇:reduce归约

    /**
     * reducing
     * 这一块可以参考Java Stream非官方教程|第四篇:reduce归约 比较类似
     */
    @Test
    public void testReducing() {
        Integer wo = listUser.stream()
                .filter(user -> user.getName().substring(0, 2).equals("wo"))
                .collect(reducing(0, User::getAge, (i, j) -> i + j));
        log.info(wo.toString());

        Integer wo2 = listUser.stream()
                .filter(user -> user.getName().substring(0, 2).equals("wo"))
                .collect(reducing(0, User::getAge, Integer::sum));
        log.info(wo2.toString());
    }

执行结果
在这里插入图片描述

2.2元素分组

2.2.1 多级分组

 /**
     * 多级分组
     */
    @Test
    public void testGroupingByLevel() {
        //先按年龄,再按等级
        Map<Integer, Map<String, List<User>>> wo = listUser.stream().collect(groupingBy(User::getAge,
                groupingBy(user -> {
                            if (user.getName().substring(0, 2).equals("wo")) {
                                return "level1";
                            } else {
                                return "level2";
                            }
                        }
                )
        ));
        log.info(wo.toString());
    }

执行结果
在这里插入图片描述

2.2.2 groupingBy+maxBy

   /**
     * 多级分组 最大
     * 获取不同性别中年龄最大
     */
    @Test
    public void testGroupingByLevelMax() {
        Map<String, Optional<User>> collect = listUser.stream().collect(groupingBy(User::getSex,
                maxBy(comparingInt(User::getAge))
        ));
        log.info(String.valueOf(collect));
    }

执行结果
在这里插入图片描述

2.2.3 groupingBy+counting

    /**
     * 多级分组 count
     */
    @Test
    public void testGroupingByLevelCount() {
        //先按年龄,再按等级
        Map<String, Long> collect = listUser.stream().collect(groupingBy(User::getSex, counting()));
        log.info(String.valueOf(collect));
    }

执行结果
在这里插入图片描述

2.2.4 groupingBy+mapping

写了两种不同的版本,set和list,set会去掉重复元素

    /**
     * 多级分组 mapping
     */
    @Test
    public void testGroupingByMapping() {
        Map<String, List<String>> wo = listUser.stream().collect(groupingBy(User::getSex,
                mapping(user -> {
                    if (user.getName().substring(0, 2).equals("wo")) {
                        return "level1";
                    } else {
                        return "level2";
                    }
                }, toList())
        ));
        log.info(String.valueOf(wo));


        Map<String, Set<String>> woSet = listUser.stream().collect(groupingBy(User::getSex,
                mapping(user -> {
                    if (user.getName().substring(0, 2).equals("wo")) {
                        return "level1";
                    } else {
                        return "level2";
                    }
                }, toSet())
        ));
        log.info(String.valueOf(woSet));
    }

执行结果
在这里插入图片描述

2.3元素分区

分区是分组的特殊情况,由一个 谓词(返回一个布尔值的函数)作为分类函数,称为分区函数。
通俗来讲就是现在的grouping 只能按true或者false进行分类。

2.3.1 partitioningBy

    /**
     * 分区 Partitioned
     */
    @Test
    public void testPartitioned() {
        Map<Boolean, List<User>> map = listUser.stream().collect(partitioningBy(user -> user.getSex().equals("男")));
        log.info(String.valueOf(map));

        Map<Boolean, List<User>> map2 = listUser.stream().collect(partitioningBy(User::isMan));
        log.info(String.valueOf(map2));
    }

执行结果
按男(true)或者女(false)进行分组
在这里插入图片描述
在这里插入图片描述

2.3.1 partitioningBy+counting

    /**
     * 分区 Partitioned counting
     */
    @Test
    public void testPartitionedCounting() {
        final Map<Boolean, Long> map = listUser.stream().collect(partitioningBy(user -> user.getSex().equals("男"), counting()));
        log.info(String.valueOf(map));
    }

执行结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值