如今的一些高级编程语言都会提供各类开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各类实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是咱们常常使用的集合类之一,不少的业务代码都离不开它,今天就来看看 List 列表的一些坑。java
第一个坑:Arrays.asList 方法返回的 List 不支持增长、删除操做编程
例如咱们执行如下代码:数组
List<String> strings = Arrays.asList("m", "g"); strings.add("h");
会抛出 java.lang.UnsupportedOperationException 异常,此时你心里 OS what?明明返回的 ArrayList 为啥不能往里面增长元素,这之后还能好好的增长元素吗?,而后果断开启 Debug 大法:数据结构
发现返回的 ArrayList 并非咱们经常使用的 java.util.ArrayList,而是 Arrays 的内部类 java.util.Arrays.ArrayList。进入方法 Arrays.asList 源码以下:框架
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
方法返回的是 Arrays 的静态内部类 java.util.Arrays.ArrayList,该类虽然和 java.util.ArrayList 也继承自抽象类 java.util.AbstractList ,可是经过该类的源码发现它并无对抽象父类 AbstractList 的 add 方法默认就是抛出 java.lang.UnsupportedOperationException 异常。dom
这个坑的根本缘由是咱们调用返回的 strings 的 add 方法是继承自抽象父类的 add 方法,而抽象父类的方法默认就是抛出 java.lang.UnsupportedOperationException 这个异常。编程语言
第二个坑,Arrays.asList 方法返回的新 List 和该方法原始入参数组修改会相互影响ide
Arrays.asList 方法除了上面这个 不支持增长、删除元素 这个坑以外,还有另一个坑:ui
从以上代码能够发现,对原始数组的修改会影响咱们经过 Arrays.asList 方法得到的新 List,深刻 java.util.Arrays.ArrayList 的源码:code
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } ... }
能够发现是直接使用了原始的数组,全部当咱们使用 Arrays.asList 方式得到的 List 时要特别注意,由于共享了数组,相互修改时可能产生一些意想不到的 Bug。标准的姿式之一是将其做为 ArrayList 构造方法的参数从新 new 一个 List 出来便可(e.g. ListstringList = new ArrayList<>(Arrays.asList(arrays)))或者经过 Guava 库中的 Lists.newArrayList ,将返回的新 List 和原始的数组解耦,就不会再互相影响了。
第三个坑,直接遍历 List 集合删除元素会报错
在直接遍历集合元素时增长、删除元素会报错,好比执行以下代码:
List<String> stringList = Lists.newArrayList("m", "g", "h"); for (String s : stringList) { if (Arrays.asList("m", "h").contains(s)) { stringList.remove(s); } }
以上代码能够正常编译经过,可是执行时会抛出 java.util.ConcurrentModificationException 异常,查看其源码能够发现,删除元素方法 remove 会使集合结构发生修改,也就是 modCount(集合实际修改的次数)会修改,在循环过程当中,会比较当前 List 的集合实际修改的次数 modCount 与迭代器修改的次数 expectedModCount ,而 expectedModCount 是初始化时的 modCount, 两者不相等,就会报 ConcurrentModificationException 异常。解决方法主要有两种方式,1.使用 ArrayList 的迭代器方式遍历,而后调用其中的方法。2.在 JDK 1.8+ 能够使用 removeIf 方法进行删除操做。
最后扎心一问:调用 ArrayList 的 remove 方法传入 int 基本类型的数字和 Integer 包装类型的数字,执行结果是否是同样的?