概述
列表中搜索不同元素通常是程序员工作的内容之一。从Java8开始,包含streams,我们有1个新的函数式方法处理数据。
stream对象有1个distinct()方法,它返回去除重复元素的集合。(如果2个元素都相同,那么stream默认保留第1个元素)。
例如:原集合中有(A1, A2, A2)四个元素,那么distinct()方法返回为(A1, A2)。在原集合中取第1个A2,第2个A2被移除。
通过比较返回集合包含的个数是否与原集合包含的个数相同,来判断原集合里是否有重复元素。
stream的对比
stream对象的distinct()方法根据Object类的equal()方法进行对比。即使用对象的哈希值来比较2个元素是否相同,比如:
ClearingDetail clearingDetail = new ClearingDetail();
ClearingDetail clearingDetail2 = new ClearingDetail();
这2个对象的哈希值如下:
ClearingDetail@56399b9e,
ClearingDetail@34b9eb03
这2个元素是不同的。
即使这2个对象的内容相同但是在stream看来,这2个就是不同的。因为distinct()方法根据Object类的equal()方法进行对比。
那么,我们如何使用集合中对象的特定属性来对比呢?
答案是,我们要编写1个维护状态的过滤器。
使用状态过滤器
这是1个函数,它返回1个谓词。
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
为了测试它,我们建立1个Person类
public class Person {
private int age;
private String name;
private String email;
// standard getters and setters
}
验证结果
我们建立1个集合,并对第2个、第3个对象添加相同的姓名,并设置过滤器对Person类的name属性进行对比。代码如下:
Person person1 = new person();
Person1.name("张三");
Person person2 = new person();
Person2.name("李四");
Person person3 = new person();
Person3.name("李四");
List<Person> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);
/**
* 是否有重复数据
* @param list 需要判重的list
* @return true,有重复。false,无重复。
*/
public boolean isRepeat(List<Person> list) {
long count = list.stream().filter(distinctByKey(Person::getName)).distinct().count();
return count < list.size();
}
/**
* 返回无重复元素的集合
*
* @return
*/
public List isRepeat(List<Person> list) {
List<ClearingDetail> collect = clearingDetailsLlist.stream().filter(distinctByKey(ClearingDetail::getBorrowApplyId)).collect(Collectors.toList());
collect.size();
return collect;
}
我们查看打印日志:
原集合
[Person@56399b9e, Person@34b9eb03, Person@78a0ff63]
过滤后返回的新集合
[Person@56399b9e, Person@34b9eb03]