当前位置: 首页 > news >正文

避免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陷阱:优雅处理结构性修改的方法

临近年终&#xff0c;项目交付排期比较紧张&#xff0c;导致很多时候&#xff0c;Code Review 往往是走马观花&#xff0c;没有严格执行。最近&#xff0c;一个实习生就产生了一个十分低级的代码BUG。笔者感觉这个问题&#xff0c;对于实习生&#xff0c;尤其是刚入职的 应届 J…...

微信小程序(三十六)事件传参

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.传参步骤 2.传参接收解构步骤 源码&#xff1a; index.wxml <button type"primary" bind:tap"onclick" mark:index"{{0}}" mark:remb"{{1}}" class"But&quo…...

编译原理与技术(三)——语法分析(二)自顶向下-递归下降

一、语法分析的两种方法 自顶向下&#xff08;Top-down&#xff09;&#xff1a; 针对输入串&#xff0c;从文法的开始符号出发&#xff0c;尝试根据产生式规则推导&#xff08;derive&#xff09;出该输入串。 从根部开始构造语法树。 自底向上&#xff08;Bottom-up&#…...

okhttp 的 拦截器

拦截器有很多作用&#xff0c;实现就是责任链模式&#xff0c;细节&#xff0c;等我有时间补上。 后面有时间更新一下。 OkHttp最核心的工作是在 getResponseWithInterceptorChain() 中进行&#xff0c;在进入这个方法分析之前&#xff0c;我们先来了 解什么是责任链模式&…...

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学设计模式之原型模式

如果对象的创建成本比较大&#xff0c;而同一个类的不同对象之间差别不大&#xff08;大部分字段都相同&#xff09;&#xff0c;在这种情况下&#xff0c;我们可以利用对已有对象&#xff08;原型&#xff09;进行复制&#xff08;或者叫拷贝&#xff09;的方式来创建新对象&a…...

博客|基于Springboot的个人博客系统设计与实现(源码+数据库+文档)

个人博客系统目录 目录 基于Springboot的个人博客系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能实现 &#xff08;1&#xff09;用户管理 &#xff08;2&#xff09;文章分类管理 &#xff08;3&#xff09;公告信息管理 &#xff08;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上传文件不允许重名

需求&#xff1a; 用户可以多文件上传 &#xff0c;在上传到服务器之前需要检查服务器中有无重名的文件&#xff0c;如果有会返回重名文件的名称数组&#xff0c;这些文件需要一个一个的向用户确认是否要覆盖重传。确认完毕后再上传到服务器。 检查文件重名&#xff1a; //上传…...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Video媒体组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Video媒体组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Video媒体组件 用于播放视频文件并控制其播放状态的组件。 子组件 无 接口…...

Linux操作系统运维-Docker的基础知识梳理总结

Linux操作系统运维-Docker的基础知识梳理总结 docker用来解决不同开发人员软件调试时环境不统一的问题&#xff0c;保证了程序调试时运行环境的一致性。docker的设计理念便是一处镜像&#xff0c;处处运行&#xff0c;即通过产生用户软件&#xff0c;运行环境及其运行配置的统一…...

PMP考试成绩如何查询?

PMP考试成绩已经陆续出来了&#xff0c;出成绩时间大概一周左右&#xff0c;没收到的别着急&#xff0c;先把如何查询成绩路径弄清楚。 【如何查询成绩】 1、输入网址&#xff08;PMI官网&#xff0c;不知道网址的私戳&#xff09;&#xff0c;点击 Log In 如果忘记 PMI 的账…...

【Scala】 2. 函数

2. 函数 scala运算符、if … else …两部分和C语言类型&#xff0c;这里不再赘述&#xff0c;这里从for循环开始讲讲scala和c/c的不同之处。 2.1 for循环 scala中主要包含to和until两个关键字&#xff0c;下面分别看看两者的用法&#xff0c;看例子就行了。 (1) to的用法 …...

14.0 Zookeeper环球锁实现原理

全局锁是控制全局系统之间同步访问共享资源的一种方式。 下面介绍zookeeper如何实现全民锁&#xff0c;讲解他锁和共享锁两类全民锁。 排他锁 排他锁&#xff08;Exclusive Locks&#xff09;&#xff0c;又被称为写锁或独占锁&#xff0c;如果事务T1对数据对象O1加上排他锁…...

课时16:本地变量_普通变量

2.2.2 普通变量 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 变量分类 所谓的本地变量就是&#xff1a;在当前系统的某个环境下才能生效的变量&#xff0c;作用范围小。本地变量按照变量值的生成方式包含两种&#xff1a;普通…...

阿里云服务器centos_7_9_x64位,3台,搭建k8s集群

目录 1.环境信息 2.搭建过程 2.1 安装Docker源 2.2 安装Docker 2.3 安装kubeadm&#xff0c;kubelet和kubectl 2.4 部署Kubernetes Master(node1) 2.5 安装Pod网络插件&#xff08;CNI&#xff09; 2.6 加入Kubernetes Node 2.7 测试kubernetes集群 3.部署 Dashboard…...

代码随想录第二十八天

第七章 回溯算法part04 ​ ● 93.复原IP地址 ​ ● 78.子集 ​ ● 90.子集II 详细布置 93.复原IP地址 本期本来是很有难度的&#xff0c;不过 大家做完 分割回文串 之后&#xff0c;本题就容易很多了 题目链接/文章讲解&#xff1a;https://programmercarl.com/0093.%E5…...

【python】绘制爱心图案

以下是一个简单的Python代码示例&#xff0c;它使用turtle模块绘制一个代表爱和情人节的心形图案。 首先&#xff0c;请确保计算机上安装了Python和turtle模块。然后&#xff0c;将以下代码保存到一个.py文件中&#xff0c;运行它就可以看到爱心图案的绘制过程。 import turt…...

在 Elastic Agent 中为 Logstash 输出配置 SSL/TLS

要将数据从 Elastic Agent 安全地发送到 Logstash&#xff0c;你需要配置传输层安全性 (TLS)。 使用 TLS 可确保你的 Elastic Agent 将加密数据发送到受信任的 Logstash 服务器&#xff0c;并且你的 Logstash 服务器从受信任的 Elastic Agent 客户端接收数据。 先决条件 确保你…...

Vue中对虚拟DOM的理解

作为现代前端开发中的主流框架之一&#xff0c;Vue.js是一个非常流行的JavaScript框架&#xff0c;其核心概念之一就是虚拟DOM&#xff08;Virtual DOM&#xff09;。在本篇文章中&#xff0c;我们将深入探讨Vue中虚拟DOM的概念&#xff0c;并讨论为什么它在前端开发中如此重要…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...