场景描述
在做需求中,有很多情况会出现 对一个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源码如下
1 2 | public E remove( int index); //执行删除指定位置的元素的功能 public boolean remove(Object o) //执行删除指定元素的功能 |
remove(int index)在删除指定index位置时有以下3步
-
- 先获取指定位置的元素用于返回值
- 将指定位置以后的每个元素向前挪一位覆盖
- 将数据最后一位 元素置空并将size减1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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来判断引用是否相同
从第一个找到即删除并返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)