本文内容都是个人思索,并未找到官方文档,请大佬评论指正:
需求:对根据对象里面的特定字段,完成对象元素去重;
public class Test4 {
static List ans = Lists.newArrayList(new User(“a”),
new User(“a”), new User(“b”), new User(“c”));
public staticPredicate distinctByKey(Function super T, ?> keyExtractor) { Set
}
普通版
普通写法:在外部定义一个Set集合,然后利于set的add方法完成去重。
public static void main(String[] args) {
//流式去重
Set seen = new HashSet<>();
ans.stream().filter(a -> seen.add(a.getName())).collect(Collectors.toList());
}
但是能不能将去重逻辑抽取为一个通用的静态方法:
进阶版
public static Predicate distinctByKey(Function super T, ?> keyExtractor) {
Set seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
使用方式:
public static void main(String[] args) {
//流式去重
Set seen = new HashSet<>();
ans.stream().filter(distinctByKey(User::getName)).collect(Collectors.toList());
}
但是细心的小伙伴可以发现,因为Stream流会多次执行filter操作,是不是会多次调用distinctByKey逻辑,每一次都创建一个Set集合,如何达到去重的效果呢???在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
打印日志:
public static void main(String[] args) {
//lambda表达式传入java.util.function类型
List collect = ans.stream()
.map(r -> {
System.out.println("前置map操作" + r);
return new UserEx(r.name);
})
.filter(distinctByKey(UserEx::getName))
.peek(r -> System.out.println("后置peek操作" + r))
.collect(Collectors.toList());
}
public static Predicate distinctByKey(Function super T, ?> keyExtractor) {
Set
执行效果:
—>创建seen:[]
前置map操作Test4.User(name=a)
filter操作Test4.UserEx(name=a)
后置peek操作Test4.UserEx(name=a)
前置map操作Test4.User(name=a)
filter操作Test4.UserEx(name=a)
前置map操作Test4.User(name=b)
filter操作Test4.UserEx(name=b)
后置peek操作Test4.UserEx(name=b)
前置map操作Test4.User(name=c)
filter操作Test4.UserEx(name=c)
后置peek操作Test4.UserEx(name=c)
[Test4.UserEx(name=a), Test4.UserEx(name=b), Test4.UserEx(name=c)]
可以看到:在最开始的时候,Set只创建了一次,在执行filter操作时,并未创建Set。
推测:stream 第一步先构建管道,第二步数据才真正流转。
后续可以利用这个特效来提供一个更加便利的工具方法。



