浅谈Java list.remove( )方法需要注意的两个坑
作者:DeMonnnnnn 发布时间:2023-02-01 06:08:44
list.remove
最近做项目的过程中,需要用到list.remove()方法,结果发现两个有趣的坑,经过分析后找到原因,记录一下跟大家分享一下。
代码
直接上一段代码,进行分析。
public class Main {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();//数据集合
List<Integer> integerList = new ArrayList<>();//存储remove的位置
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("d");
stringList.add("e");
integerList.add(2);
integerList.add(4);//此处相当于要移除最后一个数据
for (Integer i :integerList){
stringList.remove(i);
}
for (String s :stringList){
System.out.println(s);
}
}
}
如上代码我们有一个5个元素的list数据集合,我们要删除第2个和第4个位置的数据。
第一次运行
咦,为什么执行两次remove(),stringList的数据没有变化呢?
没有报错,说明代码没有问题,那问题出在哪呢?
仔细分析我们发现,remove()这个方法是一个重载方法,即remove(int position)和remove(object object),唯一的区别是参数类型。
for (Integer i :integerList){
stringList.remove(i);
}
仔细观察上面代码你会发现,其实i是Integer对象,而由于Java系统中如果找不到准确的对象,会自动向上升级,而(int < Integer < Object),所以在调用stringList.remove(i)时,其实使用的remove(object object),而很明显stringList不存在Integer对象,自然会移除失败(0.0),Java也不会因此报错。
如果我们想使用remove(int position)方法,只能降低对象等级,即修改代码;
for (Integer i :integerList){
int a =i;
stringList.remove(a);
}
第二次运行
我们发现提示在坐标为4的地方越界了,这是为什么呢?
其实很简单,因为执行stringList.remove(2)后,list.size()就-1为4了,我们原来要移除的最后一个位置的数据移动到了第3个位置上,自然就造成了越界。
我们修改代码先执行stringList.remove(4),再执行执行stringList.remove(2)。
integerList.add(4);
integerList.add(2);
这个错误提醒我们:使用remove()的方法时,要先从大到小的位置移除。当然如果你知道具体的对象,直接移除remove(对象)更稳妥。
第三次执行
嗯,这次没问题了。
总结
1、使用remove()的方法时,要先从大到小的位置移除。当然如果你知道具体的对象,直接移除remove(对象)更稳妥。
2、要密切注意自己调用的remove()方法中的,传入的是int类型还是一个对象。
补充知识: 关于List.remove()报错的问题
我们如果想删掉List中某一个对象,我们可能就会想到会用List.remove()方法。但是这样如果后续操作这个list的时候就会报错。
具体的原因是当你操作了List的remove方法的时候,他回去修改List的modCount属性。
导致抛出异常java.util.ConcurrentModificationException。
最好的想要修改List对象,我们可以用ListIterator。
就像这样:
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
arrayList.add(Integer.valueOf(i));
}
ListIterator<Integer> iterator = arrayList.listIterator();
while (iterator.hasNext()) {
if(需要满足的条件){
iterator.remove();//删除操作
iterator.add(integer);//新增操作
}
}
这样就不会去修改List的modCount属性。
来源:https://demon.blog.csdn.net/article/details/75057512


猜你喜欢
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个
- 在项目中引入springcloud中的gateway时报以下错误Description:Parameter 0 of method modi
- 前言上一篇文章用贝塞尔曲线画了一个看起来不错的小红点功能,技术上没什么难度,主要就是数学上的计算。这篇文章也差不多,模仿了一个常用的滑动解锁
- 一、使用方法查找DLL文件,通过Reflection反射类库里的各种方法来操作dll文件二、步骤加载DLL文件Assembly assemb
- 示例代码如下:namespace SampleListT{ class Program { &
- 本文较为详细的讲述了Android下Activity全屏显示实现方法。分享给大家供大家参考。具体方法如下:方法一:使用xml的方法,在该项目
- 实例如下:/** * 将一个list均分成n个list,主要通过偏移量来实现的 * @param source * @return */ p
- 前言在spring cloud的项目中用到了feign组件,简单配置过后即可完成请求的调用。又因为有向请求添加Header头的需求,查阅了官
- Queue接口先看下Queue的继承关系和其中定义的方法:Queue继承自Collection,Collection继承自Iterable。
- 产生背景为了解决异步线程产生的回调地狱//传统回调方式api.login(phone,psd).enquene(new Callback&l
- 前言本文将带您了解在 Flutter 中制作翻转卡片动画的两个完整示例。第一个示例从头开始实现,第二个示例使用第三方包。闲话少说,让我们动手
- 在Android开发中,我们经常使用列表控件,而有时候列表控件条目中又会是多条目数据,这时候,我们无法确定每个条目的数据多少,而为了美观,我
- SpringBoot使用过滤器、 * 和 * 一、SpringBoot使用过滤器Spring boot过滤器的使用(两种方式)使用sprin
- 游戏介绍:拼图游戏是一款经典的益智游戏,游戏难度分为 简单、正常、困难 三种难度,分别对应3*3,4*4,5*5布局,游戏开始前图片被随机打
- 该方法针对idea版本(2020.2.x)C:\Users\yanghao\AppData\Roaming\JetBrains\Intell
- JDK * ,代理接口没有实现类,实现 * JDK代理,代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代
- 本文实例讲述了Java后台线程操作。分享给大家供大家参考,具体如下:一 点睛有一种线程,它是后面运行的,它的任务是为其他线程提供服务,这种线
- 本文实例为大家分享了C#实现语音播报功能的具体代码,供大家参考,具体内容如下环境:window10vs2019 16.5.5.netfram
- 背景在我们日常开发中,多线程管理一直是非常头疼的问题之一,尤其在历史性长,结构复杂的app中,线程数会达到好几百个甚至更多,然而过多的线程不
- 写在前面:使用springboot作为web框架,方便开发许多,做分布式开发,dubbo又不可少,那么怎么整合在一起呢,跟我学一遍,至少会用