问题分析
.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)中。