list.remove的使用分析
场景描述
在做需求中,有很多情况会出现 对一个list遍历并过滤掉其中特定的数据 这种场景 。但是按照平常的使用方式,发现报错了。
public static void main(String[] args) {
String str1 = new String("abcde");
String str2 = new String("abcde");
String str3 = new String("abcde");
String str4 = new String("abcde");
String str5 = new String("abcde");
List list = new ArrayList();
list.add(str1);
list.add(str2);
list.add(str3);
list.add(str4);
list.add(str5);
System.out.println("list.size()=" + list.size());
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
}
}
System.out.println("after remove:list.size()=" + list.size());
}
运行结果不是:
list.size()=5
after remove:list.size()=0
居然是:
list.size()=5
after remove:list.size()=2
原因:List每remove掉一个元素以后,后面的元素都会向前移动,此时如果执行i=i+1,则刚刚移过来的元素没有被读取。
源码分析
查看arrayList源码如下
public E remove(int index); //执行删除指定位置的元素的功能
public boolean remove(Object o) //执行删除指定元素的功能
remove(int index)在删除指定index位置时有以下3步
- 先获取指定位置的元素用于返回值
- 将指定位置以后的每个元素向前挪一位覆盖
- 将数据最后一位 元素置空并将size减1
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
remove(Object o)
判断object o 是否为null 如果为null 用 ==来判断,如果不为null 用 equals来判断引用是否相同
从第一个找到即删除并返回
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
删除 List 中的元素会产生两个问题:
- 删除元素后 List 的元素数量会发生变化;
- 对 List 进行删除操作可能会产生并发问题;
解决方案
倒过来遍历
1.倒过来遍历list
for (int i = list.size()-1; i > =0; i--) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
}
}
2.每移除一个元素以后再把i移回来
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("abcde")) {
list.remove(i);
i=i-1;
}
}
3.使用iterator.remove()方法删除
for (Iterator it = list.iterator(); it.hasNext();) {
String str = (String)it.next();
if (str.equals("chengang")){
it.remove();
}
}
list.remove的使用分析的更多相关文章
- Java ArrayList在foreach中remove的问题分析
目录 iterator itr.hasNext 和 itr.next 实现 倒数第二个元素的特殊 如何避坑 都说ArrayList在用foreach循环的时候,不能add元素,也不能remove元素, ...
- LinkedList add remove get 代码分析
add void linkLast(E e) { //e 要添加的元素 final Node<E> l = last; // 最后一个元素 final Node<E> newN ...
- ThreadLocal源码分析:(三)remove()方法
在ThreadLocal的get(),set()的时候都会清除线程ThreadLocalMap里所有key为null的value. 而ThreadLocal的remove()方法会先将Entry中对k ...
- HashMap源码分析(一)
前言:相信不管在生产过程中还是面试过程中,HashMap出现的几率都非常的大,因此有必要对其源码进行分析,但要注意的是jdk1.8对HashMap进行了大量的优化,因此笔者会根据不同版本对HashMa ...
- Netty源码分析第7章(编码器和写数据)---->第4节: 刷新buffer队列
Netty源码分析第七章: 编码器和写数据 第四节: 刷新buffer队列 上一小节学习了writeAndFlush的write方法, 这一小节我们剖析flush方法 通过前面的学习我们知道, flu ...
- Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第2节: FastThreadLocal的set方法
Netty源码分析第八章: 高性能工具类FastThreadLocal和Recycler 第二节: FastThreadLocal的set方法 上一小节我们学习了FastThreadLocal的创建和 ...
- JDK源码分析(一)——ArrayList
目录 ArrayList分析 ArrayList继承结构 ArrayList字段属性 ArrayList构造函数 重要方法 ArrayList Iterator迭代器 总结 ArrayList分析 ...
- winston写日志(译)
使用 有两种方式去使用winston,直接通过默认的logger,或者实例化自己的Logger,前者设计的目的是在你的应用程序中共享logger比较方便. 使用默认Logger 使用默认的logger ...
- winston日志管理1
Usage There are two different ways to use winston: directly via the default logger, or by instantiat ...
随机推荐
- 浮动滚动条 slimScroll
1.引入jquery 2.映入slimScrolljs :<script src="https://cdn.bootcss.com/jQuery-slimScroll/1.3.8/jq ...
- 2018 ICPC 区域赛 焦作场 D. Keiichi Tsuchiya the Drift King(计算几何)
http://codeforces.com/gym/102028/problem/D 题意:根据题中给的那个图,然后题目给你 a,b,r,d,让你求出最小的满足矩形通过弯道的w 思路:
- [Version Control]—— Git如何使用
Git是什么? Git是目前世界上最先进的分布式版本控制系统. 它没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上.既然每个人的电脑都有一 ...
- TestLink测试管理工具的使用举例—第一篇
本博客用来详细说明TestLink测试管理工具的使用方法,前两篇博客已经详细说明了TestLink工具的下载,安装及基本登录功能,本篇开始说明其工具的具体使用! 下载安装TestLink工具之后,我们 ...
- 使用jsoup轻松爬数据
刚刚学习爬虫,感觉使用jsoup爬虫挺容易的.记录一下自己爬取数据的过程. Jsoup介绍: Jsoup 是一个 Java 的开源HTML解析器,可直接解析某个URL地址.HTML文本内容.使用Jso ...
- Power BI和 Visio 集成优缺点
Power BI 的 Visio 自定义视觉,这个功能是非常值得让人兴奋的,小悦相信这是一个非常重要的开发,不仅适用于 Visio,也适用于Power BI.现在已经有越来越多的可视化,它们以更简洁的 ...
- yum 的 group的信息
查找 yum源中有哪些group及其详细信息 1:yum groupinfo '*' | less 2:yum groupinfo '*' | less +/sendmail-cf 将 sendmai ...
- 两个1/x类的广义函数
[转载请注明出处]http://www.cnblogs.com/mashiqi 2017/04/15 1.$\text{p.v.}\,\frac{1}{x}$ 因为$(x \ln x - x)' = ...
- WEBBASE篇: 第七篇, JavaScript知识1
JavaScript 1 一.JavaScript 概述什么是JavaScript: JavaScript 简称 JS,是一种专门运行于JS解释器/引擎中的解释型脚本语言JS发展史: 1.1992年N ...
- System.IO.FileSystemWatcher
这个类功能很强.可以实时监测文件系统的变化. https://msdn.microsoft.com/zh-cn/library/system.io.filesystemwatcher.aspx 事件 ...