浅谈Java list.remove( )方法需要注意的两个坑

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属性。

以上这篇浅谈Java list.remove( )方法需要注意的两个坑就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java中List遍历删除元素remove()的方法

    今天碰见根据条件进行list遍历remove的问题,第一时间就是简单for循环remove,只知道这么写不行,不安全,可是为什么呢?你想过吗?下面就关于List遍历remove的问题,深挖一下! 一.几种常见的遍历方式 1.普通for循环 2.高级for循环 3.iterator和removeIf 4.stream() 5.复制 6.普通for循环 --> 倒序方式 二.源码篇 1.普通for循环出错原因 public boolean remove(Object o) { if (o == nu

  • 解决在for循环中remove list报错越界的问题

    最近在搞一个购物车的功能,里面有一个批量删除的操作,采用的是ExpandableListView以及BaseExpandableListAdapter.视乎跟本篇无关紧要,主要是为了记录一个java基础.迭代器iterator的使用 一.错误代码(主要就是购物车的批量删除) /** * 删除选中的 */ public void delSelect() { int groupSize; if (mGropBeens != null) { groupSize = mGropBeens.size();

  • 浅谈list.removeAll()删除失败的原因及解决

    未重写hashCode() 和 equals() 方法 ! 在实体类中重写这两个方法即可 ATTENTION:若实体类中还有实体类的属性,则该实体类也要重写这两个方法 (实际开发中存在删除失败的问题,待研究.暂采用Map删除方式) 实体类: public class User { private String name; private int age; private String sex; //private Company company; // Company 类也要重写 hashCod

  • java 较大数据量取差集,list.removeAll性能优化详解

    今天在优化项目中的考勤同步功能时遇到将考勤机中的数据同步到数据库, 两边都是几万条数据的样子,老代码的做法差不多半个小时,优化后我本机差不多40秒,服务器速度会更加理想. 两个数据集取差集首先想到的方法便是List.removeAll方法,但是实验发现jdk自带的List.removeAll效率很低 List.removeAll效率低原因: List.removeAll效率低和list集合本身的特点有关 : List底层数据结构是数组,查询快,增删慢 1.List.contains()效率没有h

  • 浅谈Java list.remove( )方法需要注意的两个坑

    list.remove 最近做项目的过程中,需要用到list.remove()方法,结果发现两个有趣的坑,经过分析后找到原因,记录一下跟大家分享一下. 代码 直接上一段代码,进行分析. public class Main { public static void main(String[] args) { List<String> stringList = new ArrayList<>();//数据集合 List<Integer> integerList = new

  • 浅谈java Iterator.remove()方法的用法(详解)

    实例如下: @Test public void tt(){ List<String> list = new ArrayList<String>(); list.add( "0" ); list.add( "1" ); list.add( "2" ); list.add( "3" ); list.add( "4" ); list.add( "5" ); list.a

  • 浅谈java中unmodifiableList方法的应用场景

    java对象中primitive类型变量可以通过不提供set方法保证不被修改,但对象的List成员在提供get方法后,就可以随意add.remove改变其结构,这不是希望的结果.网上看了下,发现Collections的静态方法unmodifiableList可以达到目的.方法原型为:public static <T> List<T> unmodifiableList(List<? extends T> list);用法也很简单,传入一个List实例la,返回这个list

  • 浅谈Java编程ToString()方法重写的意义

    上一篇文章我们介绍了java tostring方法重写代码示例,接下来,我们简单聊聊java编程tostring()方法重写的意义. 1.toString()就是是重写,对于一般的对象来说都会有这个方法,其实这个方法的目的,主要就是将对象按字符串的方式输出出来:打个比方,比如一个People类,里边有name,age这两个属性, 如果你People p = new People(); p.toString(); 这么做的话,默认输出就是一个内存地址. 那么你会想到重写ToString():这个方

  • 浅谈java多线程 join方法以及优先级方法

    join: 当A线程执行到了B线程的.join()方法时,A就会等待.等B线程都执行完,A才会执行. join可以用来临时加入线程执行. 1.线程使用join方法,主线程就停下,等它执行完,那么如果该线程冻结了,主线程就挂了,这也是为什么线程要抛异常的原因 2.当两个或以上线程开启了,这个A线程才使用join方法,那么主线程还是停下,这几个个线程交替进行,直到A执行完,主线程才复活 1. tostring(),方法,获取线程具体的名字,优先级 2. 优先级代表抢资源的频率 3. java中设置有

  • 浅谈java线程join方法使用方法

    本博客简介介绍一下java线程的join方法,join方法是实现线程同步,可以将原本并行执行的多线程方法变成串行执行的 如图所示代码,是并行执行的 public class ThreadTest { //private static final Long count = 10000L; public static void main(String[] args){ long base = System.currentTimeMillis(); try { ThreadJoin t1 = new

  • 浅谈java 重写equals方法的种种坑

    重写java object类的equals方法 覆盖equals方法请遵守约定 什么情况下要覆盖equals方法 容易违反的对称性 不易察觉的传递性 覆盖equals请遵守通用约定 似乎覆盖equals方法看起来似乎是一件平常甚至极其简单的事情, 但是有许多覆盖方式会导致错误,并且会表现出超出预期的行为, 而有可能数小时也无法找到错误的位置.(比如说把参数改成了非Object类型) 1. 类的每一个实例在本质上都是唯一的 ( 从内存的角度来讲是这样的),对于代表活动而不是值(value)的类来说

  • 浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别

    Exception e中e的getMessage()和toString()方法的区别: 示例代码1: public class TestInfo { private static String str =null; public static void main(String[] args) { System.out.println("test exception"); try { if(str.equals("name")){ System.out.println

  • 浅谈java 执行jar包中的main方法

    浅谈java 执行jar包中的main方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar 执行后总是运行指定的主方法,如果 jar 中有多个 main 方法,那么如何运行指定的 main 方法呢? 用下面的命令试试看: java -classpath ****.jar ****.****.className [args] "****.****"表示"包名": "className"表示&

  • 浅谈Java泛型让声明方法返回子类型的方法

    泛型典型的使用场景是集合.考虑到大多数情况下集合是同质的(同一类型),通过声明参数类型,可免去类型转换的麻烦.本文将讨论本人阅读Spring Security源码时遇到的一个关于泛型递归模式的问题. 声明方法返回子类型 在Spring Security的源码里有一个ProviderManagerBuilder接口,声明如下 public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext

随机推荐