目录
前言
这篇文章介绍一种通过stream流对集合中的对象根据key值去重的简便方法。
一、实现原理
通过Stream流中的filter方法实现对数据的去重,具体操作是构造一个Predict对象,在Predict中通过检查数据是否存在返回断言中的布尔值。
二、实现过程
代码如下:
public static <K> Predicate<K> distinctPredicate(Function<K,Object> function){
ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>();
return (t)-> null == map.putIfAbsent(function.apply(t),true);
}
// 测试代码
public static void main(String[] args) {
HashMap<String, Object> map1 = new HashMap<>();
map1.put("key1","value1");
HashMap<String, Object> map2 = new HashMap<>();
map2.put("key1","value1");
ArrayList<Map> maps = new ArrayList<>();
maps.add(map1);
maps.add(map2);
List<Map> distinctMap= maps.stream().filter(distinctPredicate(m -> m.get("key1"))).collect(Collectors.toList());
}
对于上面代码distinctPredicate方法,我是有一点疑惑的,因为在我看来filter方法每次调用distinctPredicate方法,都会重新初始化ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>()这行代码,这就意味着,这个方法的map对象里永远只会有一个值,那么也就不会出现存在key就put的情况。如果你也有这样的疑问,下面有这个问题的答案。
三、filter过滤器的原理
下面是filter中的源码部分,通过接口中的注释可以看到filter对每一个输入的元素都执行一次predicate的test方法,从而决定集合中是否需要包含这个元素。
需要注意的是filter方法的入参是一个Predict对象,也就意味着filter每次调用的是precdict对象中的方法,并不是我们前面使用的distinctPredicate方法。distinctPredicate方法的唯一作用就是构造一个precdict对象,所以也不会重复的初始化ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>()这行代码,因此前一个放入map的数据会一致保存到stream的结束。
/**
* Returns a stream consisting of the elements of this stream that match
* the given predicate.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to each element to determine if it
* should be included
// 对每一个元素执行断言,从而判断集合中是否包含这个元素
* @return the new stream
*/
public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
Objects.requireNonNull(predicate);
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SIZED) {
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}
@Override
public void accept(P_OUT u) {
if (predicate.test(u))
downstream.accept(u);
}
};
}
};
}
总结
以上就是通过stream流对集合对象中的根据key去重的方法。如有疑问欢迎指出。。。