java 集合removeAll() 方法


问题

通过removeAll方法移除list中和list1一样的元素,定义如下函数:

 1 package com.study;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 class User {
 7 
 8     private int id;
 9     private String name;
10 
11     public User() {
12     }
13 
14     public User(int id, String name) {
15         super();
16         this.id = id;
17         this.name = name;
18     }
19 
20     public int getId() {
21         return id;
22     }
23 
24     public void setId(int id) {
25         this.id = id;
26     }
27 
28     public String getName() {
29         return name;
30     }
31 
32     public void setName(String name) {
33         this.name = name;
34     }
35 }
36 
37 public class TestRemoveAll {
38     public static void main(String[] args) {
39         List<User> list = new ArrayList<User>();
40         list.add(new User(1, "1"));
41         list.add(new User(2, "2"));
42         list.add(new User(3, "3"));
43         list.add(new User(4, "4"));
44         List<User> list1 = new ArrayList<User>();
45         list1.add(new User(1, "1"));
46         list1.add(new User(2, "2"));
47         list1.add(new User(3, "3"));
48         list1.add(new User(5, "5"));
49         list.removeAll(list1);
50         System.out.println("list remove list1 以后的大小为 " + list.size());
51     }
52 }

结果为:

 

 

 显然,这不是想要的结果。那么,为什么会出现这种结果呢?查看jdk源码:

## AbstractCollection<E> ##

 1  /**
 2      * {@inheritDoc}
 3      *
 4      * <p>This implementation iterates over this collection, checking each
 5      * element returned by the iterator in turn to see if it's contained
 6      * in the specified collection.  If it's so contained, it's removed from
 7      * this collection with the iterator's <tt>remove</tt> method.
 8      *
 9      * <p>Note that this implementation will throw an
10      * <tt>UnsupportedOperationException</tt> if the iterator returned by the
11      * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
12      * and this collection contains one or more elements in common with the
13      * specified collection.
14      *
15      * @throws UnsupportedOperationException {@inheritDoc}
16      * @throws ClassCastException            {@inheritDoc}
17      * @throws NullPointerException          {@inheritDoc}
18      *
19      * @see #remove(Object)
20      * @see #contains(Object)
21      */
22     public boolean removeAll(Collection<?> c) {
23         Objects.requireNonNull(c);
24         boolean modified = false;
25         Iterator<?> it = iterator();
26         while (it.hasNext()) {
27             if (c.contains(it.next())) {
28                 it.remove();
29                 modified = true;
30             }
31         }
32         return modified;
33     }

上边removeAll方法是通过迭代器去判断c集合中是否包含,包含即调用迭代器的remove方法。在判断包含的时候(c.contains(Object obj)),这里contains方法的源码如下:

 1 /**
 2      * {@inheritDoc}
 3      *
 4      * <p>This implementation iterates over the elements in the collection,
 5      * checking each element in turn for equality with the specified element.
 6      *
 7      * @throws ClassCastException   {@inheritDoc}
 8      * @throws NullPointerException {@inheritDoc}
 9      */
10     public boolean contains(Object o) {
11         Iterator<E> it = iterator();
12         if (o==null) {
13             while (it.hasNext())
14                 if (it.next()==null)
15                     return true;
16         } else {
17             while (it.hasNext())
18                 if (o.equals(it.next()))
19                     return true;
20         }
21         return false;
22     }

这里当对象o不为空时,迭代判断用到了Object的equals方法,而Object的equals方法指的是两个对象的引用是否相等,所以才形成了最初的问题。如果我们要判断两个对象的内容相等,这里就需要重写equals方法。

代码如下:

 1 package com.study;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 import java.util.Objects;
 6 
 7 class User {
 8 
 9     private int id;
10     private String name;
11     
12     // 省略
13 
14     @Override
15     public boolean equals(Object o) {
16         if (this == o) return true;
17         if (o == null || getClass() != o.getClass()) return false;
18         User user = (User) o;
19         return id == user.id && Objects.equals(name, user.name);
20     }
21 
22     @Override
23     public int hashCode() {
24         return Objects.hash(id, name);
25     }
26 }
27 
28 public class TestRemoveAll {
29     public static void main(String[] args) {
30         List<User> list = new ArrayList<User>();
31         list.add(new User(1, "1"));
32         list.add(new User(2, "2"));
33         list.add(new User(3, "3"));
34         list.add(new User(4, "4"));
35         List<User> list1 = new ArrayList<User>();
36         list1.add(new User(1, "1"));
37         list1.add(new User(2, "2"));
38         list1.add(new User(3, "3"));
39         list1.add(new User(5, "5"));
40         list.removeAll(list1);
41         System.out.println("list remove list1 以后的大小为 " + list.size());
42     }
43 }

这里重写equals方法推荐使用idea自动生成的,然后执行了下main方法,得到的结果如下:

 

 

 

注意:

1、要想是removeAll方法生效,只需重写equals方法即可。  

  为何这里还要重写hashcode方法,重写hashcode方法为了将数据存入HashSet/HashMap/Hashtable类时进行比较。

2、看完removeAll方法的源码后,我们看到的是双层迭代,这种方式在数据量大的情况下,势必会影响效率。所以谨慎使用removeAll()函数


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM