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 ...
随机推荐
- 【转】RAID 技术发展综述
原文地址:https://blog.csdn.net/liuaigui/article/details/4581970 摘要 :现代企业信息化水平不断提高,数据已经取代计算成为了信息计算的中心.这 ...
- jmeter接口测试基础知识2.0
如何在jmeter中上传文件:选择post方式后,选择FILES Upload--文件名称栏点击浏览,值栏写file,如果查看的时候报错,就在MIME类型中写TXT 参数化:添加学生信息:进行参数化1 ...
- ipone 5s上,字体rem遇到的问题
webapp中,12px的字体,利用rem实现自适应布局, 发现只有在ipone 5s中字体超大, 这两个class元素中字体一样大小,发现上面元素字体在ipone 5s中很大, 后来验证问题在哪里, ...
- 小程序仿QQ侧滑例子
缩放:wxml <!--page/one/index.wxml--> <view class="page"> <view class="pa ...
- PTA——蠕虫爬井
PTA 7-46 爬动的蠕虫 #include<stdio.h> int main() { ; scanf("%d%d%d",&N,&U,&D) ...
- arm-linux-ld:u-boot.lds:1: ignoring invalid character `#' in expression
在裁剪uboot的时候出现下面错误: LDS u-boot.lds LD u-boot arm-linux-: ignoring invalid character `#' in expression ...
- spring--多人开发,模块化配置
需要在配置文件中配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...
- python socket 函数介绍
socket 函数原型:socket.socket([family[,type[,proto]]]) family参数取值(协议族): socket.AF_INET -->ipv4 ...
- day 41 标准文档流 浮动
一.标准文档流 什么是标准文档流 宏观的将,我们的web页面和ps等设计软件有本质的区别,web 网页的制作,是个“流”,从上而下 ,像 “织毛衣”.而设计软件 ,想往哪里画东西,就去哪里画 标准文档 ...
- delphi XML简单处理
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...