在Java开发中,数组与集合之间的转换是一个常见的操作。Arrays.asList()
方法因其简洁的语法和便捷的使用方式,被广泛应用于将数组转换为集合(如List
)。然而,这个看似简单的方法背后却隐藏着一个大坑,如果不小心处理,可能会导致线上事故,本文也是本人自身项目遇到的惨痛经历,希望能够通过讲解这个问题,让大家在实际工作中避开这个坑。
这个问题是出现开发一个电商平台的订单系统时,遇到了类似的问题。需要将一个订单ID数组转换为一个List
, 并在后续的业务逻辑中向这个List
中添加新的订单ID。由于个人经验不足,使用了Arrays.asList()
方法,部署到线上导致在添加新订单ID时抛出了UnsupportedOperationException
异常, 整个订单处理流程中断,线上系统出现了严重的故障。
这次事故对电商平台造成了巨大的影响:
后面也是及时修复,吸取本次事故教训。
首先先简单描述一下这个事故问题,废话不多说,直接看实际业务代码,也就将一个数组转换为List
,并对这个List
进行增删操作。
java
代码解读
复制代码
`Integer[] arr = {1, 2};
List<Integer> list = Arrays.asList(arr);
list.add(3);`
上述代码看起来,没问题,编译器也没有报错。但是运行这段代码时,会抛出UnsupportedOperationException
异常,提示我们不支持添加操作。这究竟是怎么回事呢?
所以这是不是个大坑,如果在实际开发中没有进行自测,必定不会酿成重大线上事故。
上述已经知道这个使用Arrays.asList()将数组装换成List会在add情况会报错,接下来深入源码进行分析。
Arrays.asList(arr)
方法实际上返回的是一个Arrays
类的内部类ArrayList
,而不是我们常用的java.util.ArrayList
。这个内部类ArrayList
继承自AbstractList
,并没有实现add
和remove
方法。
Arrays
类的内部类ArrayList
完整源码如下:
typescript
代码解读
复制代码
`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);
}
@Override
public int size() {
return a.length;
}
@Override
public Object[] toArray() {
return a.clone();
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
@Override
public E get(int index) {
return a[index];
}
@Override
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (E e : a) {
action.accept(e);
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
E[] a = this.a;
for (int i = 0; i < a.length; i++) {
a[i] = operator.apply(a[i]);
}
}
@Override
public void sort(Comparator<? super E> c) {
Arrays.sort(a, c);
}
}`
可以看到并没有实现add和remove方法,这两个方法在父类中,默认抛出UnsupportedOperationException异常。
下面是内部源码的分析
内部类ArrayList
的限制:
Arrays.asList(arr)
返回的内部类ArrayList
是一个固定长度的列表,它没有实现add
和remove
方法。list.add(3)
时,实际上调用的是AbstractList
中的add
方法,而这个方法直接抛出了UnsupportedOperationException
异常。源码分析:
AbstractList
的add
方法如下:java
代码解读
复制代码
`public void add(int index, E element) {
throw new UnsupportedOperationException();
}`
对比ava.util.ArrayList类,很明显实现add
和remove
方法,并没有直接抛出UnsupportedOperationException
异常
通过上述源码,为了避免这个问题,需要使用java.util.ArrayList
对Arrays.asList(arr)
返回的列表进行封装,而不是直接使用,这样就可以正常进行增删操作了,详细步骤如下;
在上述代码的基础上进行代码优化修改。
java
代码解读
复制代码
Integer[] arr = {1, 2};
java
代码解读
复制代码
List<Integer> list = Arrays.asList(arr);
java.util.ArrayList
对Arrays.asList(arr)
进行封装java
代码解读
复制代码
ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(arr));
java
代码解读
复制代码
`arrayList.add(3); // 正常添加元素
arrayList.remove(1); // 正常删除元素`
最终完整代码如下:
java
代码解读
复制代码
`public class Arrays_BugDemo {
public static void main(String[] args) {
Integer[] arr = {1, 2};
List<Integer> list = Arrays.asList(arr);
// 使用ArrayList进行封装
ArrayList<Integer> arrayList = new ArrayList<>(Arrays.asList(arr));
try {
list.add(3); // 这里会报错
} catch (UnsupportedOperationException e) {
System.out.println("list.add(3) 报错: " + e.getMessage());
}
arrayList.add(3); // 现在可以正常添加元素
arrayList.forEach(System.out::println);
}
}`
运行结果,程序可以正常执行,并且最终arrayList可以添加新元素。
通过本文的详细讲解,我们可以得出以下几点结论:
Arrays.asList(arr)
返回的是一个固定长度的List
集合,没有add
和remove
具体实现方法,不能进行增删操作,否则会报错UnsupportedException
。java.util.ArrayList
进行封装,如:new ArrayList<>(Arrays.asList(arr))
。希望本文能够帮助大家避免类似的线上事故,提高代码的健壮性和可靠性。在实际开发中,务必注意Arrays.asList()
的使用场景,确保代码的正确性和稳定性。同时,也应该从这次事故中吸取教训,加强代码审查和测试,避免类似问题的再次发生。
原网址: 访问
创建于: 2024-12-05 18:33:00
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论