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
,但是通过该类的源码发现它并没有对抽象父类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 = -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
方法进行删除操作。
最后扎心一问:调用 ArrayList
的 remove
方法传入 int
基本类型的数字和 Integer
包装类型的数字,执行结果是不是一样的?
Java 集合类 List 的那些坑的更多相关文章
- Java集合类常见面试知识点总结
微信公众号[Java技术江湖]一位阿里Java工程师的技术小站 Java集合类学习总结 这篇总结是基于之前博客内容的一个整理和回顾. 这里先简单地总结一下,更多详细内容请参考我的专栏:深入浅出Java ...
- Java集合类--温习笔记
最近面试发现自己的知识框架有好多问题.明明脑子里知道这个知识点,流程原理也都明白,可就是说不好,不知道是自己表达技能没点,还是确实是自己基础有问题.不管了,再巩固下基础知识总是没错的,反正最近空闲时间 ...
- 做JavaWeb开发不知Java集合类不如归家种地
Java作为面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储.但是使用数组存储对象方面具有一些弊端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容 ...
- 【转载】Java集合类Array、List、Map区别和联系
Java集合类主要分为以下三类: 第一类:Array.Arrays第二类:Collection :List.Set第三类:Map :HashMap.HashTable 一.Array , Arrays ...
- 摘抄转载前辈们的Java集合类总结
本文摘自 Blue Sky:http://www.cnblogs.com/hubcarl JAVA 集合类介绍和使用 类关系示意图Iterable(接口) │ └--Collection (接口) ├ ...
- Java集合类简单总结(重学)
java集合类简介(重学) 一.Collection(集合).Map接口两者应该是平行关系吧. 1.Map介绍 Map是以键值(key-value)对来存放的,2个值.通过key来找到value(例: ...
- Java集合类中的哈希总结
JAVA集合类中的哈希总结 目 录 1.哈希表 2.Hashtable.HashMap.ConcurrentHashMap.LinkedHashMap.TreeMap区别 3.Hashtable.Ha ...
- Java集合类: Set、List、Map、Queue使用场景梳理
本文主要关注Java编程中涉及到的各种集合类,以及它们的使用场景 相关学习资料 http://files.cnblogs.com/LittleHann/java%E9%9B%86%E5%90%88%E ...
- Java 集合类详解(含类图)
0.参考文献 此图中蓝色为抽象类.深红色表示接口(Arrays除外).绿色表示具体容器类 1.java集合类图 1.1 1.2 上述类图中,实线边框的是实现类,比如ArrayList,LinkedLi ...
- Java集合类: Set、List、Map、Queue使用
目录 1. Java集合类基本概念 2. Java集合类架构层次关系 3. Java集合类的应用场景代码 1. Java集合类基本概念 在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的 ...
随机推荐
- linux 安装mysql8.0.11
1.使用系统的root账户 2.切换到/use/local 目录下 3.下载mysql ?wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysq ...
- KingbaseES V8R6集群运维案例之---同一主机节点部署多个集群
案例说明: 在同一主机环境,由于生产需要,需要部署两个集群:本案例详细描述了两个集群的部署过程. 注意:同一主机部署多个集群需要先部署securecmdd服务,节点之间通过securecmdd服务通讯 ...
- KingbaseES V8R3 集群运维案例--kingbase_monitor.sh启动”two master“案例
案例说明: KingbaseES V8R3集群,执行kingbase_monitor.sh启动集群,出现"two master"节点的故障,启动集群失败:通过手工sys_ctl启动 ...
- KingbaseES flashback drop table
KingbaseES 引入回收站功能,实现drop table操作的数据恢复.回收站功能默认关闭,参数名称:kdb_flashback.db_recyclebin.如果不允许一个删除的表进回收站,需要 ...
- windows系统命令行cmd查看显卡驱动版本号CUDA
Win+R 输入cmd 进入命令行 输入 nvidia-smi
- JDBCUtil 连接MYSQL数据库Java工具类
1 package com.reliable.util; 2 import java.sql.Connection; 3 import java.sql.DriverManager; 4 import ...
- 【已解决】Android----java.lang.NullPointerException:---java.lang.NullPointerException:
2021-03-06 13:26:12.274 8544-8544/com.example.helloworld E/AndroidRuntime: FATAL EXCEPTION: main Pro ...
- 汇编语言-int指令
int 指令 int 指令的格式为:int n,n为中断类型码,它的功能是引发终端过程. CPU执行int n指令,相当于引发一个n号中断的中断过程,执行过程如下. 取中断类型码n: 标志寄存器入栈, ...
- 05 Ajax请求(扩展,延伸)
05 Ajax请求(扩展,延伸) 首先, 我们用Flask创建一个后台服务器(自己做网站了哈) 目录结构: 服务端: from flask import Flask, render_template, ...
- C++ 编译器和链接器的完全指南
C++是一种强类型语言,它的编译和链接是程序开发过程中不可或缺的两个环节.编译器和链接器是两个非常重要的概念.本文将详细介绍C++中的编译器和链接器以及它们的工作原理和使用方法. 编译器 编译器是将源 ...