List数据去重在开发中是十分常见的场景,下面为大家介绍一个简单的方法:利用Set去重,但根据存储元素的不同,可以分为以下两类:
1. List中存储的是基本数据类型
下面看一段示例代码:
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d", "a", "b"));
System.out.println(list);// 输出结果:[a, b, c, d, a, b]
Set<String> set = new HashSet<>(list);
List<String> newList = new ArrayList<>(set);
System.out.println(newList);// 输出结果:[a, b, c, d]
}
}
2. List中存储的是对象类型
示例代码:
public class Test {
public static void main(String[] args) {
List<People> peopleList = new ArrayList<>();
peopleList.add(new People("Joey", "001"));
peopleList.add(new People("Joey", "001"));
peopleList.add(new People("Johnny", "002"));
peopleList.add(new People("Route", "003"));
peopleList.add(new People("Vans", "004"));
Set<People> peopleSet = new HashSet<>(peopleList);
System.out.println(peopleSet);
}
}
public class People {
private String name;
private String addrNum;
// 省略无参、有参构造器,get、set方法,toString方法
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || this.getClass() != obj.getClass()) {
return false;
}
People people = (People) obj;
return Objects.equals(name, people.name)
&& Objects.equals(addrNum, people.addrNum);
}
@Override
public int hashCode() {
return Objects.hash(name, addrNum);
}
}
如果List中存储的是对象类型,要想利用Set去重,就必须重写存储对象的equals()和hashCode()方法,为什么呢?
原因其实很简单,如下所示,HashSet的实现其实是HashMap,而HashMap中,通过key区分不同元素,key的比较顺序第一步就是计算对象的hashCode,看是否存在,第二步查找对应hashCode位置的对象是否与当前对象相等。这就需要用到hashCode()与equals()方法,equals()方法的默认实现是 ==,对于对象而言,比较的是内存中的地址。上述示例中,其实我们想要的效果是name与addrNum相等即视为同一个对象,但new的操作在堆中都是开辟新的内存空间,故两个对象的地址不一致,所以,我们必须覆写这两个方法
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
/**
* Object类中equlas的默认实现
*/
public boolean equals(Object obj) {
return (this == obj);
}
是不是非常简单,但可能有朋友会问,String并不属于基本数据类型,为什么也可以直接利用Set去重?其实,String类也重写了equals()和hashCode()方法,感兴趣的朋友可以去查看相关源码
总结:
利用HashSet去重,本质是利用了HashMap去重原理,Map/Set的key为自定义对象时,必须重写hashCode和equals
遵循如下规则(来自阿里巴巴Java开发手册):
1. 只要重写equals,就必须重写hashCode
2. 因为set存储的是不重复的对象,依据hashCode和equals进行判断,所以set存储的对象必须重写这两个方法
3. 如果自定义对象作为Map的键,那么必须重写hashCode和equals