阿里巴巴为什么这样强制从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文档中是这么描述的: ...
随机推荐
- uniapp 报错 签名不对 请检查签名是否与开放平台上填写的一致
问题描述 用签名工具 输入包名 获取签名 在微信开放平台申请app 用获取的签名申请 申请成功后 在hbuilderx上云打包apk 分享 报 签名不对 请检查签名是否与开放平台上填写的一致 ...
- Sharp7与S7NetPlus 性能测试
介绍 Sharp7和都S7NetPlus是纯C#实现的基于以太网与S7系列的西门子PLC通讯的开源库.都支持.net core 跨平台可以部署在linxu, docker,windwos 中. 测 ...
- ansible使用笔记:长期更新
ansible使用笔记 ##将/home/system.sh文件拷贝到所有服务器的/home/system.sh ansible all -m copy -a "src=/home/syst ...
- leetcode 1636
一些关于hashmap和list的用法 class Solution { public int[] frequencySort(int[] nums) { Map<Integer, Intege ...
- ajax高级(请求服务器脚本,数据库, ajxa xml文件)
请求jsp与请求普通文件不通过的地方,请求jsp可能会传参,比如搜索,用户名,页码这些 html部分:<input type="text" id="txt1&quo ...
- Python - XSS-Attribute
参考资料:https://owasp-skf.gitbook.io/asvs-write-ups/cross-site-scripting-attribute-xss-attribute/kbid-3 ...
- 【CSS】CSS字体图标iconfont
CSS字体图标iconfont展示的是图标,本质上还是字体 使用字体图标步骤: 字体图标的下载 将字体图标引入到HTML 字体图标的追加(以后添加新的小图标) 推荐下载网站 icomoon字库http ...
- 生成uui
1.安装uuid包 go get github.com/google/uuid 2.目录结构 3.uuid.go package uuid import ( "github.com/goog ...
- APP 监听手机键盘是否弹出
/** * 监听键盘是否弹出 * @param show * @param hide */ export const addEventKeyboardStatus = (show,hide)=> ...
- swiper常见问题、动态加载数据问题
swiper加载静态文件是没有问题的 swiper加载动态文件需要在请求后再加载这个函数 参考链接: https://blog.csdn.net/webzrh/article/details/781 ...