😮Stream流中的Collect居然还能这样用!

96 阅读2分钟

问题分析

.collect(Collectors.toList())这是一种基础的将流中的元素收集到 List 集合中的常见操作。但当流中的每个数据都是集合时,这种操作就不可行了。那么该如何解决呢?

解决办法

先来看看collect的源码

<R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);
supplier:提供初始容器

accumulator:处理supplier提供的初始容器和stream中的数据,注意:对stream中的每个数据都会执行一次! 处理完后交给初始容器。

combiner:将所有初始容器都合并起来成为最终结果。

基本了解collect的作用后, 下面通过一个例子让理解更深刻

List<MenuVO> list = menus.stream().map(menu -> {
    Long parentId = menu.getParentId();
    // parentId不在当前菜单ID的列表,说明为顶级菜单ID,根据此ID作为递归的开始条件节点
    if (!cacheMenuIds.contains(parentId)) {
        cacheMenuIds.add(parentId);
        return recurMenus(parentId, menus);
    }
    return new LinkedList<MenuVO>();
    //addAll是将集合的所有元素添加到此集合中
    //先创建空集合作为结果集合list的初始容器,第一个addALL是将所有流的数据返回的集合添加到集合(设为list1)中
    //第二个addALL是将list1添加到结果集合list中
}).collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);

这里说明一下:recurMenus返回的是一个List

collect方法的第一个参数ArrayList::new 作用:创建一个空集合作为初始容器

第二个参数ArrayList::addALL 作用:处理流中的所有数据,这里是将map方法所有的List集合都执行一次addALL方法,就会把所有List的集合的所有数据都放到初始容器(空集合)中。

第三个参数ArrayList::addALL作用:将初始容器执行一遍addALL,就是把初始容器的所有数据,放到最终结果集合(list)中。

拓展

如果是并发情况下,我们应该选择并行流,此时第三个参数会将所有初始容器执行一遍addALL,就是把所有初始容器的所有数据,放到最终结果集合(list)中。