避免Arrays.asList陷阱:优雅处理结构性修改的方法
临近年终,项目交付排期比较紧张,导致很多时候,Code Review 往往是走马观花,没有严格执行。最近,一个实习生就产生了一个十分低级的代码BUG。笔者感觉这个问题,对于实习生,尤其是刚入职的 应届 Java 开发工程师具有一定的普遍性。因此和大家分享一下。
问题背景
项目中有个配置,默认是3个属性值。要求开发先读取这3个配置,然后从数据库中提取所有的数据,如果数据库中的数据和默认配置不同的话,就要增加上。很自然的,我们的实习生执行了下面的判断逻辑。
public static String[] INFO = new String[]{"weibo_name", "weibo_age"};
public static List<WeiInfoBean> getAllWeiboInfo(String str) {List<String> infoList = Arrays.asList(INFO);//...代码逻辑省略infoList.add(((JSONObject) itemJson).getString("item_name"));return list;
}
在UAT环境的时候,因为配置不全,因此 getAllWeiboInfo()函数没有执行。在后续的测试中,也没有细究这方面的代码。但是上线后,系统直接抛出异常:
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.util.AbstractList.add(AbstractList.java:148)at java.util.AbstractList.add(AbstractList.java:108)at com.weibo.service.impl.WeiboServiceImpl.getAllWeiboInfo(WeiboServiceImpl.java:122)
排查过程
系统报警后,笔者第一时间接手代码,并且迅速定位到了问题的所在:实习的开发同事错误的使用了Arrays.asList()函数,并且进行了增删操作。
在将对应的代码修复后,系统恢复正常。
问题分析
在Java编程中,Arrays.asList方法是一个常见的工具,用于将数组转换为List集合。然而,在使用这个方法的过程中,有时会遇到一些报错,其中一个比较常见的是在尝试向Arrays.asList返回的List中添加元素时抛出UnsupportedOperationException异常。
Arrays.asList方法简介
Arrays.asList是Java中Arrays类提供的一个静态方法,它的主要作用是将数组转换为List。该方法接受一个数组作为参数,并返回一个包装了该数组的固定大小的List。以下是Arrays.asList方法的基本用法:
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);
在上述示例中,数组array被转换为一个包含相同元素的List集合list。
Arrays.asList的限制
尽管Arrays.asList方法提供了方便的数组转换功能,但它有一个重要的限制:返回的List是一个固定大小的List。这意味着,通过Arrays.asList返回的List对象,不能进行结构上的修改操作,例如添加、删除元素等。如果尝试对这个List执行结构上的修改操作,就会触发UnsupportedOperationException异常。
UnsupportedOperationException异常的原因
在运行时,当尝试向由Arrays.asList返回的List添加或删除元素时,会抛出UnsupportedOperationException异常。这是因为Arrays.asList返回的List是一个只读的视图,它直接映射到原始数组,不允许对其进行结构上的修改。
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);// 尝试添加元素
list.add("D"); // 抛出UnsupportedOperationException异常
在这个例子中,由于Arrays.asList返回的List是不可变的,试图添加元素"D"导致了UnsupportedOperationException异常。
源码分析
我们直接打开JDK源码进行分析
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}// ArrayList的构造函数
public ArrayList(E[] array) {this.a = Objects.requireNonNull(array);
}
在构造ArrayList时,传入的数组将直接被引用,而ArrayList的实现并没有提供对数组进行修改的方法。因此,当尝试在返回的List上执行add、remove等修改操作时,就会抛出UnsupportedOperationException异常。
其他使用中的问题
除了增删操作会导致系统报错外,Arrays.asList 方法还有其他使用上的问题,如果不加以注意,就会导致结果和想得到的不同。这里一起提出来,方便大家警醒
不要用基础数据类型转换数组
我们直接使用代码作为说明:
public static void main(String[] args) {int[] in = new int[]{1,2,3};List list =Arrays.asList(in);System.out.println(list.size());// 结果是1}
上述代码的结果为1,这是为什么呢?我们还是看一下源码:
@SafeVarargs@SuppressWarnings("varargs")public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}
在源码里,Arrays.asList方法的工作原理是将传入的数组作为参数,创建一个包装该数组的List。但是,由于Java泛型不支持基础数据类型,因此对于基础类型数组,它会将整个数组作为单一元素添加到List中,而不是将数组的每个元素都添加为List的单独元素。
我们需要修改成:
int[] intArray = {1, 2, 3, 4, 5};
List<int[]> intList = Arrays.asList(intArray);
原数组修改,会导致list同步修改
我们直接使用代码作为说明:
public static void main(String[] args) {int[] in = new int[]{1,2,3};List list =Arrays.asList(in);in[0] = 4;System.out.println(list.get(0));// 结果是4}
在使用 Arrays.asList 转换数组为列表时,生成的列表其实是基于原始数组的视图,而不是新的独立副本。这就意味着,如果修改原数组,会影响到由 Arrays.asList 返回的列表,反之亦然。
这种现象的原因在于 Arrays.asList 返回的列表是一个包装了原始数组的固定大小的列表,它直接引用原始数组,而不是复制数组元素到新的列表中。因此,对原数组的修改会在列表中反映出来,反之亦然。
如何优雅使用 Arrays.asList 方法
使用ArrayList构造新的可修改List
String[] array = {"A", "B", "C"};
List<String> list = new ArrayList<>(Arrays.asList(array));
list.add("D"); // 正常执行
通过使用ArrayList的构造函数,将Arrays.asList返回的List转换为一个新的ArrayList,就可以避免UnsupportedOperationException异常,从而可以执行结构上的修改操作。
使用Collections.unmodifiableList方法
String[] array = {"A", "B", "C"};
List<String> list = Collections.unmodifiableList(Arrays.asList(array));// 尝试添加元素
list.add("D"); // 抛出UnsupportedOperationException异常
通过使用Collections.unmodifiableList方法,可以将Arrays.asList返回的List包装为一个不可修改的List,从而禁止对其进行结构上的修改。
总结
Arrays.asList是一个在Java中方便的数组转换工具,是一个经常被开发者使用的方法。但需要注意返回的List是固定大小且不可修改的。在处理需要修改List结构的情况下,使用ArrayList构造新的List或者使用Collections.unmodifiableList进行包装是解决问题的常见方法。通过深入理解Arrays.asList方法的特性,开发者可以更好地利用这个工具,并避免常见的异常情况。通过源码分析,我们更清晰地理解了为什么Arrays.asList返回的List是不可修改的,以及如何避免相关异常。
相关文章:
避免Arrays.asList陷阱:优雅处理结构性修改的方法
临近年终,项目交付排期比较紧张,导致很多时候,Code Review 往往是走马观花,没有严格执行。最近,一个实习生就产生了一个十分低级的代码BUG。笔者感觉这个问题,对于实习生,尤其是刚入职的 应届 J…...
微信小程序(三十六)事件传参
注释很详细,直接上代码 上一篇 新增内容: 1.传参步骤 2.传参接收解构步骤 源码: index.wxml <button type"primary" bind:tap"onclick" mark:index"{{0}}" mark:remb"{{1}}" class"But&quo…...
编译原理与技术(三)——语法分析(二)自顶向下-递归下降
一、语法分析的两种方法 自顶向下(Top-down): 针对输入串,从文法的开始符号出发,尝试根据产生式规则推导(derive)出该输入串。 从根部开始构造语法树。 自底向上(Bottom-up&#…...
okhttp 的 拦截器
拦截器有很多作用,实现就是责任链模式,细节,等我有时间补上。 后面有时间更新一下。 OkHttp最核心的工作是在 getResponseWithInterceptorChain() 中进行,在进入这个方法分析之前,我们先来了 解什么是责任链模式&…...
Android:多线程下载网络图片
3.12 网络图片操作 1、通过URL请求获取网络图片 示例: 创建t_picture.xml,页面layout布局文件,一个Button按钮和一个ImageView容器显示图片。 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.a…...
跟着GPT学设计模式之原型模式
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象&a…...
博客|基于Springboot的个人博客系统设计与实现(源码+数据库+文档)
个人博客系统目录 目录 基于Springboot的个人博客系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能实现 (1)用户管理 (2)文章分类管理 (3)公告信息管理 (4&#…...
【gcc】webrtc发送侧计算 丢包率
大神的分析 : 提到: 每当收到cc-feedback或者收到RR-report的时候就能统计出丢包率,在cc-controller中就会调用SendSideBandwidthEstimation::UpdatePacketsLost()去更新丢包率,同时进行码率预估 G:\CDN\rtcCli\m98\src\modules\congestion_controller\goog_cc\send_side_b…...
elementui上传文件不允许重名
需求: 用户可以多文件上传 ,在上传到服务器之前需要检查服务器中有无重名的文件,如果有会返回重名文件的名称数组,这些文件需要一个一个的向用户确认是否要覆盖重传。确认完毕后再上传到服务器。 检查文件重名: //上传…...
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Video媒体组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Video媒体组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Video媒体组件 用于播放视频文件并控制其播放状态的组件。 子组件 无 接口…...
Linux操作系统运维-Docker的基础知识梳理总结
Linux操作系统运维-Docker的基础知识梳理总结 docker用来解决不同开发人员软件调试时环境不统一的问题,保证了程序调试时运行环境的一致性。docker的设计理念便是一处镜像,处处运行,即通过产生用户软件,运行环境及其运行配置的统一…...
PMP考试成绩如何查询?
PMP考试成绩已经陆续出来了,出成绩时间大概一周左右,没收到的别着急,先把如何查询成绩路径弄清楚。 【如何查询成绩】 1、输入网址(PMI官网,不知道网址的私戳),点击 Log In 如果忘记 PMI 的账…...
【Scala】 2. 函数
2. 函数 scala运算符、if … else …两部分和C语言类型,这里不再赘述,这里从for循环开始讲讲scala和c/c的不同之处。 2.1 for循环 scala中主要包含to和until两个关键字,下面分别看看两者的用法,看例子就行了。 (1) to的用法 …...
14.0 Zookeeper环球锁实现原理
全局锁是控制全局系统之间同步访问共享资源的一种方式。 下面介绍zookeeper如何实现全民锁,讲解他锁和共享锁两类全民锁。 排他锁 排他锁(Exclusive Locks),又被称为写锁或独占锁,如果事务T1对数据对象O1加上排他锁…...
课时16:本地变量_普通变量
2.2.2 普通变量 学习目标 这一节,我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 变量分类 所谓的本地变量就是:在当前系统的某个环境下才能生效的变量,作用范围小。本地变量按照变量值的生成方式包含两种:普通…...
阿里云服务器centos_7_9_x64位,3台,搭建k8s集群
目录 1.环境信息 2.搭建过程 2.1 安装Docker源 2.2 安装Docker 2.3 安装kubeadm,kubelet和kubectl 2.4 部署Kubernetes Master(node1) 2.5 安装Pod网络插件(CNI) 2.6 加入Kubernetes Node 2.7 测试kubernetes集群 3.部署 Dashboard…...
代码随想录第二十八天
第七章 回溯算法part04 ● 93.复原IP地址 ● 78.子集 ● 90.子集II 详细布置 93.复原IP地址 本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了 题目链接/文章讲解:https://programmercarl.com/0093.%E5…...
【python】绘制爱心图案
以下是一个简单的Python代码示例,它使用turtle模块绘制一个代表爱和情人节的心形图案。 首先,请确保计算机上安装了Python和turtle模块。然后,将以下代码保存到一个.py文件中,运行它就可以看到爱心图案的绘制过程。 import turt…...
在 Elastic Agent 中为 Logstash 输出配置 SSL/TLS
要将数据从 Elastic Agent 安全地发送到 Logstash,你需要配置传输层安全性 (TLS)。 使用 TLS 可确保你的 Elastic Agent 将加密数据发送到受信任的 Logstash 服务器,并且你的 Logstash 服务器从受信任的 Elastic Agent 客户端接收数据。 先决条件 确保你…...
Vue中对虚拟DOM的理解
作为现代前端开发中的主流框架之一,Vue.js是一个非常流行的JavaScript框架,其核心概念之一就是虚拟DOM(Virtual DOM)。在本篇文章中,我们将深入探讨Vue中虚拟DOM的概念,并讨论为什么它在前端开发中如此重要…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
