组里来了一个实习生,一行代码引发了一个惨案

大家好,我是静幽水,一名大厂全栈程序员,今天给大家分享一个案例,看似简单。却容易引发惨案。

事情是这样的,最近组里来了一个实习生,因为项目工作量大,人力比较紧张,所以就分配了一个简单的小需求给他,给一个接口增加一个出参,返回匹配到的规则编码列表,规则编码是数字类型,当没有匹配到规则时,就返回默认规则编码。他的代码是这样写的:

int[] ruleIds = new int[roleList.size()];
for (int i = 0; i++; i<roleList.size() ) {ruleIds[i] = roleList.get(i).getId;
}

ok,这里看着还没有问题,但是在最后返回结果之前,他好像突然想起了,如果没有匹配到规则的话,要返回一个默认规则Id,于是他写下来这段代码。

List<Integer> ruleIdList =  Arrays.asList(ruleIds);
if (ruleIdList.size() == 0){ruleIdList.add(defaultId)
}

后来,对于他的代码,我们都觉得比较简单,代码review的时候,都在review其他同时的,比较复杂的代码逻辑,也就忽视了他的代码,但往往你最轻视的地方,就是最容易出问题的地方。就是这个ruleIdList.add(),导致在匹配不到规则的场景下,程序抛出UnsupportedOperationException异常。而他自测和UT也没有覆盖到这种场景,导致这个定时炸弹一直存在到上线之前。还好在上线前的前一天晚上,我们发现了这个问题,才避免了惨案的发生。

后来我去询问他这样写的动机。为什么上面没有用List而是用的数组,他给的解释是因为要放int类型,List里面只能放对象,我当场吐血。难道不知道自动装箱拆箱吗,那后面为啥再转成list呢,他说,因为前端开发要的list类型。好吧,既然事已发生,也就没有过多去追问。但是产生这个异常的原因,我还是想和大家分享一下。

Arrays.asList()方法是Java中将数组转换为集合的常用方法。它接收一个数组作为参数,并返回一个固定大小的List。这个List实际上是Arrays类的私有静态内部类ArrayList的实例。它实现了List接口,但是并没有实现List接口中的一些修改集合结构的方法,如add()、remove()等。

其实这并不是一种设计上的缺陷,而是特意为之,目的就是为了提高数组到集合的转换效率,避免创建新的ArrayList对象。但是同时也带来了一些限制,即不能对返回的List进行修改操作。如果使用修改集合结构的方法,例如add()、remove(),将会抛出UnsupportedOperationException异常,就像上面的代码一样。

为了更好地理解Arrays.asList()方法的局限性,我们来看一下它的源码实现。Arrays.asList()方法是在Arrays类中定义的静态方法。

// Arrays类的源码
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);
}

从源码可以看出,Arrays.asList()方法接收可变参数,而返回的是ArrayList类的实例。这个ArrayList类是Arrays类中的一个内部类,实现了List接口。

// Arrays类的内部类ArrayList的源码
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {private final E[] array;ArrayList(E[] array) {if (array == null) {throw new NullPointerException();}this.array = array;}public E get(int index) {return array[index];}public int size() {return array.length;}// 不支持修改集合结构的方法public E set(int index, E element) {throw new UnsupportedOperationException();}public void add(int index, E element) {throw new UnsupportedOperationException();}public E remove(int index) {throw new UnsupportedOperationException();}
}

从ArrayList类的源码可以看出,它继承了AbstractList类并实现了RandomAccess接口,因此支持快速随机访问。但是在ArrayList类中,修改集合结构的方法都被重写为抛出UnsupportedOperationException异常,从而保证了对返回的List进行修改的操作是不可行的。

除了Arrays.asList()方法,还存在其他类似的坑,它们在处理集合时也需要注意。

Collections.nCopies()

Collections.nCopies()方法用于创建一个指定元素重复多次的List。这个List同样是固定大小的,不能进行修改操作。

List<String> list = Collections.nCopies(3, "apple");
list.add("banana"); // 抛出UnsupportedOperationException异常

原理和Arrays.asList()类似,Collections.nCopies()方法返回的是一个AbstractList的实例,不支持修改集合结构的操作。

Arrays.asList()的嵌套问题

Arrays.asList()方法还存在一个嵌套的问题。如果使用Arrays.asList()方法将一个二维数组转换为List,会得到一个List的嵌套结构,此时对内层的List进行修改同样会抛出UnsupportedOperationException异常。

String[][] array2D = { { "apple", "banana" }, { "orange", "grape" } };
List<List<String>> nestedList = Arrays.asList(array2D);
nestedList.get(0).add("kiwi"); // 抛出UnsupportedOperationException异常

原因是这个嵌套的List中的元素仍然是固定大小的List。

这种设计是为了提高效率和节省内存开销。在转换数组到集合时,能直接使用Arrays.asList()方法的时候,它是非常方便的。但是当需要对集合进行修改操作时,应该创建一个新的ArrayList对象,并使用addAll()方法将数组元素添加进去,以避免UnsupportedOperationException异常的发生。

代码示例:

String[] array = { "apple", "banana", "orange" };
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.add("grape"); // 正常添加元素到集合中

或者如下:

List<String> Ids = new ArrayList<>(Arrays.asList(array));
Ids.add(id);

Collections.unmodifiableList()方法的不可修改特性

Collections.unmodifiableList()方法返回的是一个不可修改的List。它采用了装饰器模式,对原始List进行了封装,重写了修改集合结构的方法并抛出UnsupportedOperationException异常。

List<String> originalList = new ArrayList<>();
originalList.add("apple");
List<String> unmodifiableList = Collections.unmodifiableList(originalList);
unmodifiableList.add("banana"); // 抛出UnsupportedOperationException异常

总结: 在使用Arrays.asList()方法将数组转换为集合时,注意其局限性。返回的List是一个固定大小的List,不支持修改集合结构的方法。类似的坑还有Collections.nCopies()方法和Arrays.asList()的嵌套问题,它们同样需要注意不能对返回的集合进行修改操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rocky Linux 9安装后ssh不能登录

Rocky Linux是CentOS的原创始人发行的版本&#xff0c;为的是解决CentOS停服问题&#xff0c;该版本是基于Red Hat Enterprise Linux 9的下游发布。 在Rocky Linux 9版本中&#xff0c;为了增加安全性&#xff0c;默认情况下禁用SSH root密码登录。这是系统默认设定的规则&…

Docsify介绍—md文件直接生成网页的工具

Markdown是一种轻量级标记语言&#xff0c;它使用易读易写的纯文本格式&#xff0c;用于编写文档&#xff0c;如README&#xff0c;wiki&#xff0c;博客文章等。Markdown语言最初由约翰格鲁伯&#xff08;John Gruber&#xff09;和亚伦斯沃茨&#xff08;Aaron Swartz&#x…

什么是HTTP状态码?常见的HTTP状态码有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是HTTP状态码&#xff1f;⭐ 1xx - 信息性状态码⭐ 2xx - 成功状态码⭐ 3xx - 重定向状态码⭐ 4xx - 客户端错误状态码⭐ 5xx - 服务器错误状态码⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前…

华为云云耀云服务器L实例评测|用PHP从数据库到后端到前端完整实现一个中秋节祝福语项目

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

大数据知识点之大数据5V特征

大数据的特征可以浓缩为五个英文单词&#xff0c;Volume(大量&#xff09;、Variety(多样性&#xff09;、Velocity(速度&#xff09;、Value(价值&#xff09;、Veracity(准确性&#xff09;。因为是5个特征都是以“V”开头的英文单词&#xff0c;又叫大数据5V特征。 概述&…

Putty连接服务器

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

k8s1.20集群域名与集群ip解析详解及使用案例

目录 一.k8s中的域名解析浅析 1.单机 2.k8s的容器中 二.k8s不同版本对应的dns域名服务组件

代理IP和Socks5代理:跨界电商与爬虫的智能引擎

跨界电商&#xff0c;作为全球市场的一部分&#xff0c;对数据的需求越来越大。同时&#xff0c;随着互联网的发展&#xff0c;爬虫技术也在不断演进&#xff0c;成为了跨界电商的关键工具之一。然而&#xff0c;随之而来的是网站的反爬虫机制和网络安全风险。在这种情况下&…

学习 CodeWhisperer 的一些总结

目前一些常见的的 AI 工具 GitHub Copilot&#xff1a;GitHub 与 OpenAI 合作开发的一个人工智能助手。 Codeium&#xff1a;是一个免费的人工智能驱动的代码生成工具 Tabnine&#xff1a;一个自动代码生成工具&#xff0c;免费版本非常有限&#xff0c;只提供简短的代码完成…

Java版本spring cloud + spring boot企业电子招投标系统源代码

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审…

Qt消息机制和事件

事件 事件是由Qt或者系统在不同时刻发出的,当敲下鼠标,或者按下键盘,或者当窗口需要重新绘制的时候,就会发出一个相应的事件,一些操作由用户的操作发出,一些则由系统自动发出,如系统定时器事件等。 Qt 中所有事件类都继承于 QEvent。 在事件对象创建完毕后, Qt 将这个…

【数据结构】二叉树的层序遍历(四)

目录 一&#xff0c;层序遍历概念 二&#xff0c;层序遍历的实现 1&#xff0c;层序遍历的实现思路 2&#xff0c;创建队列 Queue.h Queue.c 3&#xff0c;创建二叉树 BTree.h BTree.c 4&#xff0c;层序遍历的实现 一&#xff0c;层序遍历概念 层序遍历&#xff1a;除了先序…

面试官:什么是虚拟DOM?如何实现一个虚拟DOM?说说你的思路

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、什么是虚拟DOM 二、为什么需要虚拟DOM 三、如何实现虚拟DOM 小结 一、什么是虚拟DOM 虚拟 DOM &#xff08…

Android13适配-Google官方照片视频选择器

官方照片选择器 图 1. 照片选择器提供了一个直观的界面&#xff0c;便于与您的应用分享照片。 照片选择器的界面可供浏览和搜索&#xff0c;并按日期降序向用户显示其媒体库中的文件。如隐私保护最佳实践 Codelab 中所示&#xff0c;照片选择器为用户提供了一种安全的内置授权…

Nginx配置SSL证书

1 Ubuntu 20.04 上安装 Nginx Nginx 发音 “engine x” ,是一个开源软件&#xff0c;高性能 HTTP 和反向代理服务器&#xff0c;用来在互联网上处理一些大型网站。它可以被用作独立网站服务器&#xff0c;负载均衡&#xff0c;内容缓存和针对 HTTP 和非 HTTP 的反向代理服务器。…

API接口采集电商平台阿里巴巴中国站获得1688商品评论数据货品评分、评价内容接口调用指南

淘宝API商品评论接口&#xff0c;主要用于获取某个商品的评价信息。通过该接口&#xff0c;我们可以获取到商品的所有评价内容、评价时间、评价等级等相关信息&#xff0c;帮助我们更好地了解用户对商品的反馈&#xff0c;进而进行数据分析和业务优化。 1688.item_review-获得…

java项目之咖啡馆管理系统ssm+jsp

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的咖啡馆管理系统。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&am…

算法课作业1

https://vjudge.net/contest/581138 A - Humidex 模拟题 题目大意 给三个类型数字通过公式来回转化 思路 求e的对数有log函数&#xff0c;不懂为什么不会出精度错误&#xff0c;很迷&#xff0c;给的三个数字也没有顺序&#xff0c;需要多判断。 #include<cstdio>…

C++设计模式_04_Strategy 策略模式

接上篇&#xff0c;本篇将会介绍C设计模式中的Strategy 策略模式&#xff0c;和上篇模板方法Template Method一样&#xff0c;仍属于“组件协作”模式&#xff0c;它与Template Method有着异曲同工之妙。 文章目录 1. 动机&#xff08; Motivation&#xff09;2. 代码演示Stra…

STP介绍

目录 STP概述 二层环路带来的问题 1.广播风暴 2.MAC地址漂移问题 3.多帧复制---这个好理解&#xff0c;同一个数据帧被重复收到多次&#xff0c;被称为多帧复制。 802.1D生成树 STP的BPDU BPDU主要分为两大类 配置BPDU RPC COST 配置BPDU的工作过程 TCN BPDU TCN…