JDK8的对象去重方式的总结,不包含常规的去重方式,例如:List、Set(HashSet)、TreeSet和LinkedHashSet的遍历去重方式。包含lambda表达式的去重方式、Stream API的去重方式,distinct
如果有解释错误的地方,欢迎留言指正哦!!!
lambda表达式去重有两个值得注意的点,一个是JDK8的四大内置函数式接口。另一个ConcurrentHashMap集合。
这里用到了ConcurrentHashMap的putIfAbsent方法,这也是该去重方法的核心。该方法存入的参数会生成一对键值对保存,**如果集合中没有存入过该键值对,那么会返回null,如果已经存入了,那么返回该key对应的value。配合JDK8的Predicate断言式函数式接口,如果是null 那么表示还没存入即没有重复,返回true。那么调用该方法时,通过filter将返回值为true的对象保留。**则实现的对集合中对象的某一属性去重。
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
附上putIfAbsent方法的源码:
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
该方法的核心是TreeSet。我们都知道,默认情况下,TreeSet可以实现去重并且按照自然顺序排序。同样的,还有HashSet以及LinkedHashSet都可以实现去重,但对于实体类对象,后两者的去重与实体类中equals和hashCode方法的实现有关。
要实现对实体类对象的去重需要引入比较器(或者实体类需要实现Comparable中的compareTo方法)。如果不使用比较器,那么将会报错(只针对TreeSet,HashSet以及LinkedHashSet都不会报错);
java.lang.ClassCastException: com.asiainfo.grid.sop.base.po.GsopKpiPool cannot be cast to java.lang.Comparable
接下来,我们使用TreeSet来去重。TreeSet根据Comparator中写入的对象的某一属性去重
Set<GsopKpiPool> gsopKpiPools = new TreeSet<>(Comparator.comparing(GsopKpiPool::getSourceTable));
gsopKpiPools.addAll(cpList);
gsopKpiPools.forEach(t->System.out.println(t));
System.out.println("-----------------------将TreeSet转换成List");
ArrayList<GsopKpiPool> gsopKpiPools1 = Lists.newArrayList(gsopKpiPools);
gsopKpiPools1.forEach(t->System.out.println(t));
Collectors的collectingAndThen方法,则是执行完Collector之后,将该集合以某种格式返回
cpList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(GsopKpiPool::getSourceTable))), ArrayList::new));
//上述代码相当于
cpList.stream().collect(Collectors.toCollection(()->new ArrayList<>(new TreeSet<>(Comparator.comparing(GsopKpiPool::getSourceTable)))));
使用该方法对实体类对象去重需要重写实体类的equals和hashCode方法。否则起不到任何去重的效果。
List<GsopKpiPool> collect = cpList.stream().distinct().collect(Collectors.toList());
equals和hashCode方法的重写就不多做解释啦……