当前位置:主页 > 动态 >

记录Java 集合类 List 的坑

时间:2020-12-20 23:49:46

  java基础教程栏目介绍集合类包含 Map 和 Collection 两个大类

  (免费):java基础教程

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

  第一个坑:Arrays.asList 方法返回的 List 不支持增加、删除操作

  例如我们执行以下代码:

  List<String> strings = Arrays.asList("m", "g"); strings.add("h");

  会抛出 异常,此时你内心 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 异常。

  这个坑的根本原因是我们调用返回的 strings 的 add 方法是继承自抽象父类的 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 = -5198L; 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 集合删除元素会报错

  在直接遍历集合元素时增加、删除元素会报错,比如执行如下代码:

  以上代码可以正常编译通过,但是执行时会抛出 java.util.ConcurrentModificationException 异常,查看其源码可以发现,删除元素方法 remove 会使集合结构发生修改,也就是 modCount(集合实际修改的次数)会修改,在循环过程中,会比较当前 List 的集合实际修改的次数 modCount 与迭代器修改的次数 expectedModCount ,而 expectedModCount 是初始化时的 modCount, 二者不相等,就会报 ConcurrentModificationException 异常。解决方法主要有两种方式,1.使用 ArrayList 的迭代器方式遍历,然后调用其中的方法。2.在 JDK 1.8+ 可以使用 removeIf 方法进行删除操作。

  最后扎心一问:调用 ArrayList 的 remove 方法传入 int 基本类型的数字和 Integer 包装类型的数字,执行结果是不是一样的?

热点推荐
1 XBIT DEX:黎巴嫩预计月底前正式承认以色

消息,预测市场显示,黎巴嫩预计将在本月底前正式承认以色列为主权国家,目前市场对此的...

2 XAI:Grok 4.5在SpaceX和特斯拉进入私人测试

XAI宣布其Grok 4.5版本现已在SpaceX和特斯拉进行私人测试,并计划在今年每月推出新的AI模型。...

3 美国政府拟建立战略比特币储备,计划购

美国政府拟建立战略比特币储备,计划购买总量为105万枚比特币,占比特币总量的5%。...

4 乌克兰首次将被扣押虚拟资产移交至国家

乌克兰总检察长办公室表示,乌克兰首次将被扣押的虚拟资产移交至国家资产追回和管理局管...

5 Coinbase、OKX争夺Binance用户,MiCA截止日期临

消息,Coinbase和OKX正在争夺欧洲加密用户,此举是在Binance暂停多个欧盟服务后进行的。此变化...

6 OpenAI升级Codex体验:支持长对话悬停跳转

消息,OpenAI本周发布Codex更新,解决了长对话导航不便与界面元素缩放错位问题。针对长对话场...

7 Token实际成本降至0.99美元,SemiAnalysis披露

消息,SemiAnalysis报告显示,内部大模型token支出已占员工总薪资的30%,人均月消费近50亿个tok...

8 特朗普称美军打击伊朗导弹和无人机储存

消息,美国总统特朗普当地时间27日表示,美军刚刚打击了伊朗的导弹和无人机储存地点,以及...

9 Fidelity Digital Assets:比特币减半不会削弱

消息,Fidelity Digital Assets在最新研究报告中表示,比特币减半并不会削弱网络长期安全性。矿工...

10 以太坊面临更深跌幅,沉睡鲸鱼出售

消息,沉睡的以太坊鲸鱼首次出售自2017年以来的以太坊钱包,增加了市场供应,导致以太坊价...

成都来彰科技 蜀ICP备2025134723号-1

资讯来源互联网,如有版权问题请联系管理员删除。