一.前言
在项目中经常会碰到按某些属性是否相同去去除List集合中的重复对象的问题,每次看网上写的都是什么 “重写自定义对象的equlas和hashCode”,千篇一律全是这样,但是真实项目中自定义的对象可能在多个地方用到,每个地方的去重方式都可能不一样,重写肯定是不行的,今天就总结一下不重写对象的equlas和hashCode,去除List中的重复对象。
二. 实现方式
假设我们有个对象User, 包含四个属性: name、nickName、age、dept,需要根据name和age这两个属性去重,如果这两个属性相同就代表同一个对象
public class User {
// 姓名
private String name;
// 昵称
private String nickName;
// 年龄
private Integer age;
// 部门
private String dept;
// 此处省略set和get方法
}
在list集合中添加5个User对象,分别如下:
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("张三", "三儿", 20, "销售部"));
userList.add(new User("李四", "四儿", 23, "销售部"));
userList.add(new User("张三", "三儿", 20, "销售部"));
userList.add(new User("张三", "三儿", 20, "研发部"));
userList.add(new User("王五", "五儿", 21, "研发部"));
}
现在我们想要去除userList集合中拥有相同姓名和年龄的User,但是又不想重写User实体类的equlas和hashCode方法,那么该怎么做呢?
第一种方式:for循环倒叙删除:
即:使用两层循环,内层循环从后往前删
// int size = userList.size(); 此处一定不要在这里将size写死,因为size是一直在变的
for (int i = 0; i < userList.size(); i ++) {
User outU = userList.get(i);
for (int j = userList.size() - 1; j > i; j--) { // 内层循环从 size() -1开始
User inU = userList.get(j);
if (inU.getName().equals(outU.getName()) && inU.getAge() == outU.getAge()) {
userList.remove(j);
}
}
}
结果如下:
已经成功的删除掉了相同姓名和年龄的对象。
第二种方式:使用Set集合去除重复元素:
Set<User> set = new TreeSet<>(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
// 这里按照自己的需求来添加属性即可
return (o1.getName().compareTo(o2.getName())) + (o1.getAge() - o2.getAge()));
};
});
set.addAll(userList);
printList(new ArrayList<>(set));
开始在这里有点疑问,当时不明白为什么加入一个new Comparator比较器重写compart方法就可以去重呢? 一个“比较”的方法还能够去重? 后来看了一个Set的源码搞明白了,其实Set集合的底层是用Map实现的,去重的原理即是用到了比较,首先看hashCode是否相同,如果相同再去比较equals,如果equals也相同就不再存储,而我们的比较器Comparator,正是实现这个比较。