详解Java 集合类 List 的那些坑

 更新时间:2020年08月23日 15:56:25   作者:mghio  
这篇文章主要介绍了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 包装类型的数字,执行结果是不是一样的?

到此这篇关于详解Java 集合类 List 的那些坑的文章就介绍到这了,更多相关Java List集合类坑 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现获取cpu、内存、硬盘、网络等信息的方法示例

    Java实现获取cpu、内存、硬盘、网络等信息的方法示例

    这篇文章主要介绍了Java实现获取cpu、内存、硬盘、网络等信息的方法,涉及java使用第三方jar包针对本机硬件的cpu、内存、硬盘、网络信息等的读取相关操作技巧,需要的朋友可以参考下
    2018-06-06
  • Java开发完整短信验证码功能的全过程

    Java开发完整短信验证码功能的全过程

    利用短信验证码进行身份验证是目前互联网众多产品常用的一种方式,那么这种短信验证功能是如何实现的呢,下面这篇文章主要给大家介绍了关于Java开发完整短信验证码功能的相关资料,需要的朋友可以参考下
    2021-10-10
  • 关于Mybatis使用collection分页问题

    关于Mybatis使用collection分页问题

    项目中mybatis分页的场景是非常高频的,当使用ResultMap并配置collection做分页的时候,我们可能会遇到获取当前页的数据少于每页大小的数据问题。接下来通过本文给大家介绍Mybatis使用collection分页问题,感兴趣的朋友一起看看吧
    2021-11-11
  • JAVA 对接腾讯云直播的实现

    JAVA 对接腾讯云直播的实现

    这篇文章主要介绍了JAVA 对接腾讯云直播的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • 详解MongoDB和Spring整合的实例代码

    详解MongoDB和Spring整合的实例代码

    这篇文章主要介绍了详解MongoDB和Spring整合的实例代码,Spring提供了MongoTemplate这样一个模板类的实现方法,简化了具体操作。有兴趣的可以了解一下
    2017-07-07
  • MyBatis 添加元数据自定义元素标签的实现代码

    MyBatis 添加元数据自定义元素标签的实现代码

    这篇文章主要介绍了MyBatis 添加元数据自定义元素标签的实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Java容器源码LinkedList原理解析

    Java容器源码LinkedList原理解析

    这篇文章主要介绍了Java容器源码LinkedList原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • java 如何判断是否可以ping通某个地址

    java 如何判断是否可以ping通某个地址

    这篇文章主要介绍了java 如何判断是否可以ping通某个地址,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • SpringBoot生成二维码的实现

    SpringBoot生成二维码的实现

    这篇文章主要介绍了SpringBoot生成二维码的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • java使用mybatis调用存储过程返回一个游标结果集方式

    java使用mybatis调用存储过程返回一个游标结果集方式

    这篇文章主要介绍了java使用mybatis调用存储过程返回一个游标结果集方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01

最新评论