Java踩坑之List的removeAll方法

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

  1. List<Long> ids1 = Arrays.asList(1L, 3L, 2L);
  2. List<Long> ids2 = Collections.singletonList(2L);
  3. List<Long> ids3 = new ArrayList<>();
  4. ids3.add(1L);
  5. ids3.add(2L);
  6. List<Long> 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. * <p>This method also provides a convenient way to create a fixed-size
  9. * list initialized to contain several elements:
  10. * <pre>
  11. * List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
  12. * </pre>
  13. *
  14. * @param <T> 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 <T> List<T> asList(T... a) {
  21. return new ArrayList<>(a);
  22. }
  1. private static class ArrayList<E> extends AbstractList<E>
  2. implements RandomAccess, java.io.Serializable
  3. {
  4. private static final long serialVersionUID = -2764017481108945198L;
  5. private final E[] a;
  6.  
  7. ArrayList(E[] array) {
  8. a = Objects.requireNonNull(array);
  9. }
  10.  
  11. @Override
  12. public int size() {
  13. return a.length;
  14. }
  15.  
  16. @Override
  17. public Object[] toArray() {
  18. return a.clone();
  19. }
  20.  
  21. @Override
  22. @SuppressWarnings("unchecked")
  23. public <T> T[] toArray(T[] a) {
  24. int size = size();
  25. if (a.length < size)
  26. return Arrays.copyOf(this.a, size,
  27. (Class<? extends T[]>) a.getClass());
  28. System.arraycopy(this.a, 0, a, 0, size);
  29. if (a.length > size)
  30. a[size] = null;
  31. return a;
  32. }
  33.  
  34. @Override
  35. public E get(int index) {
  36. return a[index];
  37. }
  38.  
  39. @Override
  40. public E set(int index, E element) {
  41. E oldValue = a[index];
  42. a[index] = element;
  43. return oldValue;
  44. }
  45.  
  46. @Override
  47. public int indexOf(Object o) {
  48. E[] a = this.a;
  49. if (o == null) {
  50. for (int i = 0; i < a.length; i++)
  51. if (a[i] == null)
  52. return i;
  53. } else {
  54. for (int i = 0; i < a.length; i++)
  55. if (o.equals(a[i]))
  56. return i;
  57. }
  58. return -1;
  59. }
  60. ...... //看的出来,这个list是可以修改的 但是要通过set方法
  61. }

所以调用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 <T> 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 <T> List<T> singletonList(T o) {
  11. return new SingletonList<>(o);
  12. }
  1. private static class SingletonList<E>
  2. extends AbstractList<E>
  3. implements RandomAccess, Serializable {
  4.  
  5. private static final long serialVersionUID = 3093736618740652951L;
  6.  
  7. private final E element;
  8.  
  9. SingletonList(E obj) {element = obj;}
  10.  
  11. public Iterator<E> iterator() {
  12. return singletonIterator(element);
  13. }
  14.  
  15. public int size() {return 1;}
  16.  
  17. public boolean contains(Object obj) {return eq(obj, element);}
  18.  
  19. public E get(int index) {
  20. if (index != 0)
  21. throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
  22. return element;
  23. }
  24.  
  25. // Override default methods for Collection
  26. @Override
  27. public void forEach(Consumer<? super E> action) {
  28. action.accept(element);
  29. }
  30. @Override
  31. public boolean removeIf(Predicate<? super E> filter) {
  32. throw new UnsupportedOperationException();
  33. }
  34. @Override
  35. public void replaceAll(UnaryOperator<E> operator) {
  36. throw new UnsupportedOperationException();
  37. }
  38. @Override
  39. public void sort(Comparator<? super E> c) {
  40. }
  41. @Override
  42. public Spliterator<E> spliterator() {
  43. return singletonSpliterator(element);
  44. }
  45. }
  46. // 可以看出 这个list是一个只读的list 并未对外提供编辑方法

    同样会调用AbstractCollection的removeAll方法

    

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

 

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

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

posted on 2020-12-23 11:25  云淡风轻博客  阅读(8121)  评论(1编辑  收藏  举报