分组:Stream不得不知的操作
Posted 沛沛老爹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分组:Stream不得不知的操作相关的知识,希望对你有一定的参考价值。
场景
假如现在存在两个列表List<A> 和List<B> 。
其中A包含 B的集合。
代码如下。
A对象
@Data
public void A
private Integer id;
private String name;
private List<B> bList;
B 对象
@Data
public void B
private Integer AId;
private String name;
private String storeName;
private Long startTime;
private BigDecimal amount;
...
现在需要将符合条件的List<B>的内容set到List<A>中
用来组合出一个新的VO返回出去。
常规解决方案
一般解决方法都是直接使用for循环操作。
先讲List<A>循环,然后根据条件,找到对应的List<B>的对象List,
一条条set到A中去。
常规伪代码
List<A> listA;
List<B> listB;
listA.foreach(a->
List<B> newListB = new ArrayList<>();
for(int i=0;i<listB.size();i++)
if(a.id==listB[i].AId)
newListB.add(listB[i]);
a.setBList(newListB);
);
我们可以看到,在常规操作里面,可以看到当前会有大量的循环。
循环影响性能,这个事情我们就不作过多讨论了。
而且代码看起来的话,大量的嵌套和判断,导致代码的自读性差。
Stream常规操作
如果熟悉stream的话,
一般都会把里面嵌套的那层for使用stream来操作。
例如
List<A> listA;
List<B> listB;
listA.foreach(a->
List<B> newListB = listB.stream.filter(e->e.getAId==a.getId).collect(Collectors.toList());
a.setBList(newListB);
);
上面的stream操作也会产生很多的对象
同时,每次循环都会将listB全部比对一次。
在性能上来讲,还是有待提高。
那么有没有一种比较优雅的方案呢?
在这里,推荐一种新的方案。
新解决方案
Stream的groupingBy方法
使用这个方法的源码在Collectors中。
groupingBy源码
public final class Collectors
...
/* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param classifier the classifier function mapping input elements to keys
* @return a @code Collector implementing the group-by operation
*
* @see #groupingBy(Function, Collector)
* @see #groupingBy(Function, Supplier, Collector)
* @see #groupingByConcurrent(Function)
*/
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier)
return groupingBy(classifier, toList());
...
通过groupingBy的分类器,可以直接将当前List<B>中的数据,进行分类。
这样得到的数据就可以直接赋值了。
示例
我们还是拿原来的代码来操作
List<A> listA;
List<B> listB;
//跳过赋值操作
Map<Integer,List<B>> bMap = listB.stream.collect(Collectors.groupingBy(B::getAId));
listA.foreach(a->
a.setBList(bMap.get(a.getId()));
);
我们将listB直接进行分组,使用map进行存储。map对应的key就是groupingBy中的分类器B::getAId。value就是对应的分组的数据。
这样一看,我们的代码非常简洁。
总结
groupingBy在分类操作的时候非常有用,我们可以直接将数据分好组。在后续需要调用的时候,直接get就好,就不需要进行二次计算操作了。在执行速度和代码可读性方面都有不错的提升。
顺便再上面的中间,再加点料,如果需要根据AId来对分组的amount属性求和。这样的话,你会怎样做呢?
以上是关于分组:Stream不得不知的操作的主要内容,如果未能解决你的问题,请参考以下文章