乐趣区

关于java:Java-集合类-List-的那些坑

当初的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的汇合框架中就提供了各种实现,汇合类蕴含 Map 和 Collection 两个大类,其中 Collection 上面的 List 列表是咱们常常应用的汇合类之一,很多的业务代码都离不开它,明天就来看看 List 列表的一些坑。

第一个坑: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,然而通过该类的源码发现它并没有对形象父类 AbstractListadd 办法默认就是抛出 java.lang.UnsupportedOperationException 异样。

这个坑的根本原因是咱们调用返回的 stringsadd 办法是继承自形象父类的 add 办法,而形象父类的办法默认就是抛出 java.lang.UnsupportedOperationException 这个异样。

第二个坑,Arrays.asList 办法返回的新 List 和该办法原始入参数组批改会相互影响

Arrays.asList 办法除了下面这个 不反对减少、删除元素 这个坑之外,还有另外一个坑:

从以上代码能够发现,对原始数组的批改会影响咱们通过 Arrays.asList办法取得的新 List,深刻 java.util.Arrays.ArrayList 的源码:

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. List<String> stringList = 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 办法进行删除操作。

最初扎心一问:调用 ArrayListremove 办法传入 int 根本类型的数字和 Integer 包装类型的数字,执行后果是不是一样的?

退出移动版