Java踩坑之List的removeAll方法
阅读原文时间:2023年07月10日阅读:2

最近在公司写东西,发现List的removeAll方法报错 Demo代码如下:

  1. List ids1 = Arrays.asList(1L, 3L, 2L);

  2. List ids2 = Collections.singletonList(2L);

  3. List ids3 = new ArrayList<>();

  4. ids3.add(1L);

  5. ids3.add(2L);

  6. List ids = new ArrayList<>();

  7. ids.add(2L);

  8. System.out.println("==== 001");

  9. ids1.removeAll(ids); // 这一步会报错

  10. System.out.println("==== 002");

  11. ids2.removeAll(ids); // 这一步也会报错

  12. System.out.println("==== 003");

  13. ids3.removeAll(ids);

001报错的原因是:Arrays.asList 返回的List是自己内部实现的ArrayList 而不是util下的ArrayList对象

  1. /**

  2. * Returns a fixed-size list backed by the specified array. (Changes to //明确指出 返回的是固定大小的list

  3. * the returned list "write through" to the array.) This method acts

  4. * as bridge between array-based and collection-based APIs, in

  5. * combination with {@link Collection#toArray}. The returned list is

  6. * serializable and implements {@link RandomAccess}.

  7. *

  8. *

    This method also provides a convenient way to create a fixed-size

  9. * list initialized to contain several elements:

  10. *

  11. * List stooges = Arrays.asList("Larry", "Moe", "Curly");

  12. *

  13. *

  14. * @param the class of the objects in the array

  15. * @param a the array by which the list will be backed

  16. * @return a list view of the specified array

  17. */

  18. @SafeVarargs

  19. @SuppressWarnings("varargs")

  20. public static List asList(T… a) {

  21. return new ArrayList<>(a);

  22. }

  23. private static class ArrayList extends AbstractList

  24. implements RandomAccess, java.io.Serializable

  25. {

  26. private static final long serialVersionUID = -2764017481108945198L;

  27. private final E[] a;

  28. ArrayList(E[] array) {

  29. a = Objects.requireNonNull(array);

  30. }

  31. @Override

  32. public int size() {

  33. return a.length;

  34. }

  35. @Override

  36. public Object[] toArray() {

  37. return a.clone();

  38. }

  39. @Override

  40. @SuppressWarnings("unchecked")

  41. public T[] toArray(T[] a) {

  42. int size = size();

  43. if (a.length < size)

  44. return Arrays.copyOf(this.a, size,

  45. (Class) a.getClass());

  46. System.arraycopy(this.a, 0, a, 0, size);

  47. if (a.length > size)

  48. a[size] = null;

  49. return a;

  50. }

  51. @Override

  52. public E get(int index) {

  53. return a[index];

  54. }

  55. @Override

  56. public E set(int index, E element) {

  57. E oldValue = a[index];

  58. a[index] = element;

  59. return oldValue;

  60. }

  61. @Override

  62. public int indexOf(Object o) {

  63. E[] a = this.a;

  64. if (o == null) {

  65. for (int i = 0; i < a.length; i++)

  66. if (a[i] == null)

  67. return i;

  68. } else {

  69. for (int i = 0; i < a.length; i++)

  70. if (o.equals(a[i]))

  71. return i;

  72. }

  73. return -1;

  74. }

  75. …… //看的出来,这个list是可以修改的 但是要通过set方法

  76. }

所以调用removeAll方法的时候 会调用AbstractList的父类AbstractCollection的removeAll方法:

  1. public boolean removeAll(Collection c) {

  2. Objects.requireNonNull(c);

  3. boolean modified = false;

  4. Iterator it = iterator();

  5. while (it.hasNext()) {

  6. if (c.contains(it.next())) {

  7. it.remove();

  8. modified = true;

  9. }

  10. }

  11. return modified;

  12. }

ArrayList是数组 在循环的时候删除元素 一定会出现问题

002报错的原因是与001类似:Collections.singletonList的返回值SingletonSet也是自己的内部类

  1. /**

  2. * Returns an immutable list containing only the specified object. // 返回不可变的list

  3. * The returned list is serializable.

  4. *

  5. * @param the class of the objects in the list

  6. * @param o the sole object to be stored in the returned list.

  7. * @return an immutable list containing only the specified object.

  8. * @since 1.3

  9. */

  10. public static List singletonList(T o) {

  11. return new SingletonList<>(o);

  12. }

  13. private static class SingletonList

  14. extends AbstractList

  15. implements RandomAccess, Serializable {

  16. private static final long serialVersionUID = 3093736618740652951L;

  17. private final E element;

  18. SingletonList(E obj) {element = obj;}

  19. public Iterator iterator() {

  20. return singletonIterator(element);

  21. }

  22. public int size() {return 1;}

  23. public boolean contains(Object obj) {return eq(obj, element);}

  24. public E get(int index) {

  25. if (index != 0)

  26. throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");

  27. return element;

  28. }

  29. // Override default methods for Collection

  30. @Override

  31. public void forEach(Consumer action) {

  32. action.accept(element);

  33. }

  34. @Override

  35. public boolean removeIf(Predicate filter) {

  36. throw new UnsupportedOperationException();

  37. }

  38. @Override

  39. public void replaceAll(UnaryOperator operator) {

  40. throw new UnsupportedOperationException();

  41. }

  42. @Override

  43. public void sort(Comparator c) {

  44. }

  45. @Override

  46. public Spliterator spliterator() {

  47. return singletonSpliterator(element);

  48. }

  49. }

  50. // 可以看出 这个list是一个只读的list 并未对外提供编辑方法

同样会调用AbstractCollection的removeAll方法

003是我new的ArrayList对象,会调用自己内部重写的removeAll方法,针对数组重写了删除方法,不会出问题,解决001、002的问题 最简单的办法可以用new ArrayList()包一层就ok了!

究其原因还是自己对源码的研究不足!

更多技术资源请访问:https://www.zhaochao.top/articles