现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 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 的那些坑的更多相关文章

  1. Java集合类常见面试知识点总结

    微信公众号[Java技术江湖]一位阿里Java工程师的技术小站 Java集合类学习总结 这篇总结是基于之前博客内容的一个整理和回顾. 这里先简单地总结一下,更多详细内容请参考我的专栏:深入浅出Java ...

  2. Java集合类--温习笔记

    最近面试发现自己的知识框架有好多问题.明明脑子里知道这个知识点,流程原理也都明白,可就是说不好,不知道是自己表达技能没点,还是确实是自己基础有问题.不管了,再巩固下基础知识总是没错的,反正最近空闲时间 ...

  3. 做JavaWeb开发不知Java集合类不如归家种地

    Java作为面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储.但是使用数组存储对象方面具有一些弊端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容 ...

  4. 【转载】Java集合类Array、List、Map区别和联系

    Java集合类主要分为以下三类: 第一类:Array.Arrays第二类:Collection :List.Set第三类:Map :HashMap.HashTable 一.Array , Arrays ...

  5. 摘抄转载前辈们的Java集合类总结

    本文摘自 Blue Sky:http://www.cnblogs.com/hubcarl JAVA 集合类介绍和使用 类关系示意图Iterable(接口) │ └--Collection (接口) ├ ...

  6. Java集合类简单总结(重学)

    java集合类简介(重学) 一.Collection(集合).Map接口两者应该是平行关系吧. 1.Map介绍 Map是以键值(key-value)对来存放的,2个值.通过key来找到value(例: ...

  7. Java集合类中的哈希总结

    JAVA集合类中的哈希总结 目 录 1.哈希表 2.Hashtable.HashMap.ConcurrentHashMap.LinkedHashMap.TreeMap区别 3.Hashtable.Ha ...

  8. Java集合类: Set、List、Map、Queue使用场景梳理

    本文主要关注Java编程中涉及到的各种集合类,以及它们的使用场景 相关学习资料 http://files.cnblogs.com/LittleHann/java%E9%9B%86%E5%90%88%E ...

  9. Java 集合类详解(含类图)

    0.参考文献 此图中蓝色为抽象类.深红色表示接口(Arrays除外).绿色表示具体容器类 1.java集合类图 1.1 1.2 上述类图中,实线边框的是实现类,比如ArrayList,LinkedLi ...

  10. Java集合类: Set、List、Map、Queue使用

    目录 1. Java集合类基本概念 2. Java集合类架构层次关系 3. Java集合类的应用场景代码 1. Java集合类基本概念 在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的 ...

随机推荐

  1. Windows系统使用ODBC驱动访问KingaseES数据库及常见问题解决

    Windows系统使用KingbaseES ODBC驱动访问KingaseES数据库及常见问题解决. 一.获取KingbaseES数据库ODBC驱动: 在官网下载KingbaseES数据库安装包,选择 ...

  2. RedisTemplate 的简单使用

    redisTemplate.opsForValue() 方法可以获得一个 Redis String 的操作类,通过该类可以执行一系列字符串类型数据的操作,例如获取.设置.删除数据等. // 示例 1: ...

  3. #Tarjan,树的直径#CF1000E We Need More Bosses

    题目 给定一个\(n\)个点\(m\)条边的无向图,找到两个点\(s,t\),使得\(s\)到\(t\)必须经过的边最多 分析 桥就是必须经过的边,考虑给无向图缩点, 按照桥建一棵树,那么就转换成了求 ...

  4. #dp#洛谷 3473 [POI2008] UCI-The Great Escape JZOJ 4019 Path

    题目 \(n*m\)的地图,计算从\((n,1)\)到第\(x\)列的第\(y\)行的路径条数\(\bmod k\) , 走过的点不能再走,转弯只能向右转.转弯完之后必须往前走一格 分析 可以发现,走 ...

  5. #模拟#B 字串修改

    题目 有两个字符串\(s,t\),其中\(s\)只包含小写字母以及 *,\(t\)只包含小写字母. 你可以进行任意多次操作,每次选择\(s\)中的一个 *,将它修改为任意多个(可以是0个)它的前一个字 ...

  6. #贪心,树#C 平衡的树

    分析 处理出子树内剩余删减以及最大的剩余\(a\)和, 如果删了还是超过\(b\)输出无解 代码 #include <cstdio> #include <cctype> #de ...

  7. OpenHarmony装饰指定自定义组件:@BuilderParam装饰器

      当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作.若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能.为解决此问题,ArkUI ...

  8. Spring源码 20 手写模拟

    项目地址 https://gitee.com/liao-hang/hand-write-spring.git 模拟 Spring 注解 自动装配 Autowired @Target(ElementTy ...

  9. HDC2021技术分论坛:还有人不知道鸿蒙智联设备认证咋搞?

    作者:maxiansheng,华为鸿蒙智联认证测试专家 2021年5月18日,华为正式宣布原Work With HUAWEI HiLink和Powered by HarmonyOS品牌升级为Harmo ...

  10. HDC 2022 开发者主题演讲与技术分论坛干货分享(附课件)

     原文:https://mp.weixin.qq.com/s/axm6HyX0PqKCKksFxIfehg,点击链接查看更多技术内容.   11月4日-11月6日,HDC 2022在东莞成功举办,这是 ...