阿里巴巴为什么这样强制从List中删除元素
还是先举个例子,你侄女对天文知识感兴趣,然后你就用程序写了太阳系九大星系(水星、金星、地球、火星、木星、土星、天王星、海王星、冥王星)的运行轨迹图,然后拿给侄女看。然后她说错了错了,你的知识太旧了,多了一颗星。根据2006年8月24日国际天文联合大会召开,在会议上经过投票表决,冥王星被降级为矮行星,太阳系目前只剩下八颗行星。所以你需要删除一颗星。这个时候你打开电脑开始删除冥王星。

你从下面List中删除一颗星。
List<String> tempList = Arrays.asList("水星","金星","地球","火星",
"木星","土星","天王星","海王星","冥王星","冥王星");
怎么删除List中的冥王星呢?[PS为了演示某些删除方法不可靠,重复写了冥王星] 。
先写一段阿里规约:
【强制】不要再foreach循环里进行元素的remove/add操作,remove元素请使用Iterator方式,如果并发的操作,需要对Iterator对象加锁。
好了,那就让我们来写所有可能删除元素的方法

1:普通的for循环的删除(不可靠)。
List<String> list = new ArrayList(tempList);
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
if ("冥王星".equals(str)) {
list.remove(i);
}
}
System.out.println(list);
运行结果如下:
[水星, 金星, 地球, 火星, 木星, 土星, 天王星, 海王星, 冥王星]
奇了怪了,没删除干净?
问题出在 list.size(),因为 list.size() 和 i 都是动态变化的,i 的值一直在累加,list.size() 一直在减少,所以 list 就会早早结束了循环。所以这种方式虽然不会报错,但存在隐患,并且不容易被察觉,不建议使用。
2:普通的for循环提取变量进行删除(这个更不可靠,会报错)。
List<String> list = new ArrayList(tempList);
int size = list.size();
for (int i = 0; i < size; i++) {
String result = list.get(i);
if ("冥王星".equals(result)) {
list.remove(i);
}
}
System.out.println(list);
结果如下:

这更不对了,一下子搞出个下标越界。
因为 size 变量是固定的,但 list 的实际大小是不断减小的,而 i 的大小是不断累加的,一旦 i >= list 的实际大小肯定就异常了。
3:普通的for循环倒叙删除(这个用法可以,但也不推荐,倒叙看着很别扭,个人意见)。
for (int i = list.size() - 1; i > 0; i--) {
String result = list.get(i);
if ("冥王星".equals(result)) {
list.remove(i);
}
}
System.out.println(list);
运行结果如下:
[水星, 金星, 地球, 火星, 木星, 土星, 天王星, 海王星]
4:使用增强的for循环删除(会抛出异常,不推荐,注意我这次为了演示效果,把行星的顺序换一下),不少开发者喜欢用这种方式。
List<String> tempList = Arrays.asList("水星","金星","地球","火星",
"冥王星","土星","天王星","海王星","冥王星","木星");
List<String> list = new ArrayList(tempList);
for (String item : list) {
if ("冥王星".equals(item)) {
list.remove(item);
}
}
System.out.println(list);
结果如下:

奇了怪了,又抛异常了。不过这次的异常和上面的下标异常不太一样,这次是:
java.util.ConcurrentModificationException
这个是集合操作中很常见的异常之一,即并发修改异常!
增强的 for循环,其内部是调用的 Iterator 的方法,取下个元素的时候都会去判断要修改的数量(modCount)和期待修改的数量(expectedModCount)是否一致,不一致则会报错,而 ArrayList 中的 remove 方法并没有同步期待修改的数量(expectedModCount)值,所以会抛异常了。
5、迭代器循环迭代器删除(可靠,也是十分推荐的用法)。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String item = iterator.next() ;
if ("冥王星".equals(item)){
iterator.remove();
}
}
System.out.println(list);
结果如下,十分完美和正确:
[水星, 金星, 地球, 火星, 土星, 天王星, 海王星, 木星]
这是因为迭代器中的 remove 方法将期待修改的数量(expectedModCount)值进行了同步。
6:迭代器循环集合删除(这个可能很多开发者也会这样写,也可能会抛出异常的)。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String item = iterator.next() ;
if ("冥王星".equals(item)){
list.remove(item);
}
}
System.out.println(list);
结果如下:

7:Stream filter 过滤(十分推荐,当然使用这个删除需要JDK的环境在8及其8以上的版本)。
list = list.stream().filter(item -> !"冥王星".equals(item)).
collect(Collectors.toList());
System.out.println(list);
结果如下,十分完美和正确:

这个方法利用了 Stream 的筛选功能,快速过滤所需要的元素,虽然不是进行集合删除,但达到了同样的目的,这种方法要更简洁
看了上面的几个例子,相信你熟悉了List删除元素的用法了,希望你看了上面的例子,开发的时候不会再犯错了。

阿里巴巴为什么这样强制从List中删除元素的更多相关文章
- 遍历List过程中删除元素的正确做法(转)
遍历List过程中删除元素的正确做法 public class ListRemoveTest { 3 public static void main(String[] args) { 4 ...
- Jquery中删除元素方法
empty用来删除指定元素的子元素,remove用来删除元素,或者设定细化条件执行删除 语法: empty() remove(expr); empty用来删除指定元素的子元素,remove用来删除元素 ...
- /编写一个函数,要求从给定的向量A中删除元素值在x到y之间的所有元素(向量要求各个元素之间不能有间断), 函数原型为int del(int A ,int n , int x , int y),其中n为输入向量的维数,返回值为删除元素后的维数
/** * @author:(LiberHome) * @date:Created in 2019/2/28 19:39 * @description: * @version:$ */ /* 编写一个 ...
- 如何从List中删除元素
从List中删除元素,不能通过索引的方式遍历后删除,只能使用迭代器. 错误的实现 错误的实现方法 public class Demo { public static void main(Str ...
- PHP从数组中删除元素的方法
PHP从数组中删除元素的方法 本篇文章主要介绍了PHP从数组中删除元素的四种方法实例 删除一个元素,且保持原有索引不变 使用 unset 函数,示例如下: 1 2 3 4 5 <?php $ ...
- PHP从数组中删除元素的四种方法实例
PHP从数组中删除元素的四种方法实例 一.总结 一句话总结:unset(),array_splice(),array_diff(),array_diff_key() 二.PHP从数组中删除元素的四种方 ...
- MongoDB 学习笔记之 从数组中删除元素和指定数组位置
从数组中删除元素: 从数组中删除单个元素: db.ArrayTest.updateOne({ "name" : "Bill"},{$pop: {"ad ...
- javascript中的链表结构—从链表中删除元素
1.概念 上一个博文我们讲到链表,其中有一个方法remove()是暂时注释的,这个方法有点复杂,需要添加一个Previous()方法找到要删除的元素的前一个节点,这一个博文我们来分析一下这个remov ...
- php数组中删除元素之重新索引
如果要在某个数组中删除一个元素,可以直接用的unset,但今天看到的东西却让我大吃一惊 <?php $arr = array('a','b','c','d'); unset($arr[1]); ...
- Java Map在遍历过程中删除元素
Java中的Map如果在遍历过程中要删除元素,除非通过迭代器自己的remove()方法,否则就会导致抛出ConcurrentModificationException异常.JDK文档中是这么描述的: ...
随机推荐
- 【摘】python和它的内置类型子类化
python和它的内置类型子类化 看个好玩的东西 class Folder(list): def __init__(self, name): self.name = name def dir(self ...
- 【python】第二模块 步骤一 第二课、数据库表的相关操作
第二课.数据库表的相关操作 一.课程介绍 1.1 课程介绍 学习目标 管理逻辑库和数据表 创建.删除.修改逻辑库和数据表 了解常用的数据类型和约束 字符串.整数.浮点数.精确数字.日期.枚举.主要约束 ...
- java学习问题
1.nacos Connection refused: connect 由于配置文件配置错误引起的.我的nacos是部署在另一台linux服务器的,yml具体配置如下:
- spark命令
spark提交任务命令 集群方式: ./bin/spark-submit --master spark://localhost:7077 --class 类 /home/cjj/testfile/f ...
- python+selenium+unittest自动化测试
目前先用这个记录自动化测试相关内容,后期再进行整理: 1.自动化测试:testcase-->test suite ---> TestRunner 2.TestRunner时,一种将内容打 ...
- layui中文离线文档PDF下载
失效链接处理 layui中文离线文档 PDF 下载 本站整理下载: 链接:https://pan.baidu.com/s/18FbllhLEezXTn-y1eiiNKg 提取码:nuqz ...
- PHP实现JWT登录鉴权
一.什么是JWT 1.简介 JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准. 简单的说,JWT就是一种Token的编码算法,服务器端负责根据一个 ...
- String类型时间与Date时间转换
1. String类型的时间转为DateTime public static Date transferString2Date(String s) { Date date = new Date(); ...
- 【再学WPF】模板
1 <!--设置所有的按钮样式--> 2 <Style TargetType="Button"> 3 <Setter Property="M ...
- Linux基础驱动开发
开始:1.要在自己的Linux源码中创建自己的模块文件.在drivers下创建自己的文件名为myled.然后创建myleds.c文件,编写源码 2.Makefile和Kconfig的设置 在myled ...