在处理归并不同集合时去除其重复元素的时候没有什么好的方法,本来打算手撸一个去处重复元素的函数,但是想起集合类里肯定有解决这一问题的方法,就去查了一下 API ,还真有,那就是使用 removeAll() 。
boolean removeAll(Collection<?> c)
从列表中移除指定 collection 中包含的其所有元素(可选操作)。
直接用一个简单的例子来讲一下如何使用 removeAll() :
public class Problems {
private Integer id;
private String title;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title == null ? null : title.trim();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Problems )) {
return false
}
Problems that = (Problems) o;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null){
return false;
}
if (getTitle() != null ? !getTitle().equals(that.getTitle()) : that.getTitle() != null){
return false;
}
return true;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getTitle() != null ? getTitle().hashCode() : 0);
return result;
}
}
因为在执行removeAll方法时,会先对集合元素进行比较,如果元素相等才执行移除操作,说到这,相信很多人都已经明白是怎么回事了,因为不相等(equals),所以没有执行移除。也就是说直接使用 removeAll 是没有效果的,要在实体类中重写 hashCode 和 equals 方法才行。现在大多数 IDE 都支持自动生成实体类的 hashCode 和 equals 方法,不妨查一下你的 IDE 的快速生成方法,不然就得手撸了。
然后现在就可以来试一下了:
import java.util.ArrayList;
import java.util.List;
public class ProblemsList {
private List<Problems> subList;
private List<Problems> allList;
public UserList(){
subList=new ArrayList<Problems>();
allList=new ArrayList<Problems>();
for(int i=0;i<3;i++){
Problems problems=new Problems();
Problems.setId(i);
Problems.setTitle("This is"+i);
subList.add(Problems);
}
for(int i=0;i<10;i++){
Problems problems=new Problems();
Problems.setId(i);
Problems.setTitle("This is"+i);
subList.add(Problems);
}
}
public static void main(String[] args){
ProblemsList problemsList =new ProblemsList();
problemsList.allList.removeAll(problemsList.subList);//调用removeAll方法
System.out.println(problemsList.allList.size());
}
}
OK了,到这里本来可以结束了,不过不妨再深入看看 removeAll:
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
可以看到在调用removeAll方法时,其中调用了contains()方法,一块贴上源码:
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))//这里调用了equals()方法
return true;
}
return false;
}
但是很奇怪,为什么我们还要重写 hashCode 方法呢?来看官方文档:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
当 equals 方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
抓下重点:
1.如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
2.当 equals 方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
也就是说,两个对象是相等的(equals ),那么其 hashCode 结果必须相等,所以有必要重写 hashCode 方法。