java list中删除元素用remove()报错的fail-fast机制原理以及解决方案

2023-05-16

                                     java list中删除元素用remove()报错的fail-fast机制原理以及解决方案

  现在有一个list,有6个元素,值分别是1、5、5、8、5、10,现需要删除值为5的元素

  第一种

           

import java.util.ArrayList;
import java.util.List;

public class ListRemove1 {
	
	 public static void main(String args[]) {
	        List<Integer> list = new ArrayList<Integer>();
	        list.add(1);
	        list.add(5);
	        list.add(5);
	        list.add(8);
	        list.add(5);
	        list.add(10);

	        for (int j = 0; j < list.size(); j++) {
	            if (list.get(j) == 5) {
	                list.remove(j);
	            }
	        }

	        outputList(list);
	    }

	    private static void outputList(List<Integer> list) {
	        for (int i = 0; i < list.size(); i++) {
	            System.out.print(list.get(i)+"    ");
	        }
	    }

}
运行结果
     1    5    8    10  

   这结果显然不是我们的预期,我们是希望删除List中所有为5的元素,但输出结果中却出现了5,这是因为在i等于1时,删除了List中的index为1的元素5,这时候list为[1,5,8,5,10], 但接下来,i递增后,等于2,在list.get(i)时,取出来的结果就成为了8了,也就是说随着list元素的删除,index是随之变化的,这就是其中的陷阱


第二种

    

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListRemove2 {
	
	 public static void main(String args[]) {
	        List<Integer> list = new ArrayList<Integer>();
	        list.add(1);
	        list.add(5);
	        list.add(5);
	        list.add(8);
	        list.add(5);
	        list.add(10);
           
	        /*
	        for (int i1 : list) {
	            if (i1 == 5) {
	                list.remove(i1);
	            }
	        }
	        */
	        
	        Iterator<Integer>  iterator = list.iterator();
	        while(iterator.hasNext()){
	        	if(iterator.next() == 5){
	        		list.remove(5);
	        	}
	        }

	        outputList(list);
	    }

	    private static void outputList(List<Integer> list) {
	        for (int i = 0; i < list.size(); i++) {
	            System.out.print(list.get(i)+"    ");
	        }
	    }

}
 上面代码不管用增强for循环还是用Iterator遍历list,用list.remove()方法都报下面的错误:


  

   之所以报上面的错误是因为发生了fail-fast 事件。

       fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

   1.报ConcurrentModificationException异常的原因

     ConcurrentModificationException是在操作Iterator时抛出的异常,ArrayList的Iterator是在父类AbstractList.java中实现的,具体源码:

    

	public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {


	    public Iterator<E> iterator() {
		return new Itr();
	    }

	    private class Itr implements Iterator<E> {
		/**
		 * Index of element to be returned by subsequent call to next.
		 */
		int cursor = 0;

		/**
		 * Index of element returned by most recent call to next or
		 * previous.  Reset to -1 if this element is deleted by a call
		 * to remove.
		 */
		int lastRet = -1;

		/**
		 * The modCount value that the iterator believes that the backing
		 * List should have.  If this expectation is violated, the iterator
		 * has detected concurrent modification.
		 */
		int expectedModCount = modCount;  

		public boolean hasNext() {
	            return cursor != size();
		}

		public E next() {
	            checkForComodification();
		    try {
			E next = get(cursor);
			lastRet = cursor++;
			return next;
		    } catch (IndexOutOfBoundsException e) {
			checkForComodification();
			throw new NoSuchElementException();
		    }
		}

		public void remove() {
		    if (lastRet == -1)
			throw new IllegalStateException();
	            checkForComodification();

		    try {
			AbstractList.this.remove(lastRet);
			if (lastRet < cursor)
			    cursor--;
			lastRet = -1;
			expectedModCount = modCount;
		    } catch (IndexOutOfBoundsException e) {
			throw new ConcurrentModificationException();
		    }
		}

		final void checkForComodification() {
		    if (modCount != expectedModCount)
			throw new ConcurrentModificationException();
		}
	    }

	    protected transient int modCount = 0;
	}

    ArrayList中的remove()的实现

    

	public class ArrayList<E> extends AbstractList<E> implements List<E>,
			RandomAccess, Cloneable, java.io.Serializable {
		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
		}
	}
      无论是add()、remove(),还是clear(),只要涉及到修改集合中的元素个数时,都会改变modCount的值

      从源码中我们可以看出:

          1) Iterator<Integer>  iterator = list.iterator();执行这语句时,此时Iterator中的expectedModCount = modCount(因为list有6个元素,所有该值为6),

          2)遍历到第二个元素即值为5的时候,list.remove(5);从ArrayList中的remove()实现中发现:modCount++;此时modCount的值为7

          3)在执行if(iterator.next() == 5)这语句即调用iterator的next()方法时,next()方法实现会调用checkForComodification();,该方法会执行 if (modCount != expectedModCount),即比较modCount和expectedModCount的值是否相等,此时expectedModCount的值为6而modCount的值为7,这两个值不相等,所以抛出

throw new ConcurrentModificationException();这个异常

    第三种即解决方案:调用iterator的iterator.remove()方法,该方法的实现中,会执行expectedModCount = modCount;这个语句,即expectedModCount赋值为modCount;

这样就保证expectedModCount 等于modCount,不会抛出ConcurrentModificationException()这个异常

     

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListRemove4 {
	
	 public static void main(String args[]) {
	        List<Integer> list = new ArrayList<Integer>();
	        list.add(1);
	        list.add(5);
	        list.add(5);
	        list.add(8);
	        list.add(5);
	        list.add(10);

	        Iterator<Integer>  iterator = list.iterator();
	        while(iterator.hasNext()){
	        	if(iterator.next() == 5){
	        		iterator.remove();
	        	}
	        }

	        outputList(list);
	    }

	    private static void outputList(List<Integer> list) {
	        for (int i = 0; i < list.size(); i++) {
	            System.out.print(list.get(i)+"    ");
	        }
	    }


}
运行结果:

     1    8    10 

       

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java list中删除元素用remove()报错的fail-fast机制原理以及解决方案 的相关文章

  • OSGI - 处理捆绑包所需的第 3 方 JAR

    我刚刚开始 OSGI 开发 正在努力了解如何最好地处理依赖的 JAR 也就是说 如果我要创建一个捆绑包 我很可能需要使用一些第 3 方 JAR 当我创建要部署到 OSGI 的捆绑包 JAR 时 显然不包含这些第 3 方 JAR 因此该捆绑包
  • 为什么不在下一个 JVM 中删除类型擦除呢?

    Java 在 Java 5 中引入了泛型类型擦除 因此它们可以在旧版本的 Java 上运行 这是兼容性的权衡 我们已经失去了这种兼容性 1 https stackoverflow com questions 22610400 a progr
  • 如何在android中动态添加项目到listview

    有谁能够帮助我 我正在尝试在 Android 中创建一个 ListView 并且我正在尝试使用代码 不使用 XML 将项目加载到其中 这是我到目前为止的代码 tweetList ListView this findViewById R id
  • Hibernate vs JPA vs JDO - 各自的优缺点? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我熟悉 ORM 这个概念 几年前我什至在 NET 项目中使用过 nHibernate 然而 我还没有跟上 Java 中 ORM 的主题
  • Java:是否有工具可以使代码(在第 3 方 JAR 中)向前兼容(1.4 - 1.6)

    我有一个使用 Java 1 4 编译的第 3 方 JAR 文件 有没有一个工具可以使jar文件兼容Java 1 6 类似于 retrotranslator 但它的反面是什么 我尝试反编译类文件并在 1 6 中重新编译它们 但失败了 问题是这
  • HK2 MethodInterceptor 与 Jersey 资源

    如何设置aopMethodInterceptor使用泽西岛资源 这是我尝试过的 如下this https hk2 java net 2 2 0 aop example html文档 第 1 步 拦截服务 public class MyInt
  • 原生状态栏

    有没有办法创建nativeSWT 中的状态栏与 Windows 应用程序中的状态栏类似 我见过使用标签模拟的状态栏 但我对真正的解决方案更感兴趣 org eclipse jface action StatusLineManager crea
  • 验证在子类上调用此方法时是否调用了重写的超类方法

    我将用这个例子来展示我的问题 我有一个带有方法的类foo 该类有一个重写此方法的子类 子类的方法调用超类的方法 我可以验证一下吗 我不想测试什么foo在超类中确实如此 我只需要验证它是否被调用 我知道重构可以有所帮助 优先考虑组合而不是继承
  • 从 Android Intent 打开图库应用

    我正在寻找一种打开方式Android来自意图的画廊应用程序 我不想返回图片 而是只是打开图库以允许用户使用它 就像他们从启动器中选择它一样 View pictures folders 我尝试执行以下操作 Intent intent new
  • 使用math.random在java中进行猜谜游戏

    您好 我正在尝试使用 Math random 生成 0 到 100 之间的随机数 然后要求用户输入 0 到 100 之间的数字 或 1 退出 如果数字超出范围 且不是 1 请要求用户输入新数字 如果用户没有正确猜出数字 则告诉用户随机数是否
  • 能够存储微秒的 Date 对象

    我正在寻找一个能够存储到微秒粒度的 Date 对象 有人知道吗 标准Date对象仅存储到毫秒 我知道这是平台限制 我可以通过包装来解决这个问题Date加上自定义类别中的小数数量 然而 我希望避免编写一个带有适当计算等的内容 我需要解析一个b
  • Struts 2 中的 Java 应用程序可以管理多少个会话?

    我正在开发事务管理应用程序 并且正在使用 Struts2 我在内部使用了一个会话来设置和获取值 例如 ActionContext getContext getSession put string string 在应用程序中使用这样的会话是否
  • Java:删除链表中的所有元素

    Java中如何删除链表中的所有元素without使用已经可用的clear 方法 这项练习的灵感来自于电话采访中收到的一个问题 说我可以用 C 来做这个 void DeleteAllElement ListElement head ListE
  • 从内存中获取Java类字节码(经过多次转换)

    我正在为 Minecraft 开发一个 coremod 并在加载许多类时对其进行转换 然而问题是 有多个 coremod 也转换了与我相同的类 并且我遇到了一些我想研究的奇怪行为 那么问题来了 经过多次转换后的字节码如何检查呢 当我转换它时
  • 构造函数中的同步块

    我有一个带有静态变量的类 如下所示 private static Object sMyStaticVar 如果我想在构造函数中为这个 var 赋值 我有这样的代码 if sMyStaticVar null sMyStaticVar new
  • 如何执行带有参数的命令?

    如何在 Java 中执行带有参数的命令 我试过了 Process p Runtime getRuntime exec new String php var www script php m 2 这是行不通的 String options n
  • RequestDispatcher.forward 到媒体文件?

    我最近有一个需要解决的问题 https stackoverflow com questions 19385223 how to transparently stream a file to the browser并找到了一个解决方案 但如果
  • 封闭实例的匿名类

    我正在阅读 Joshua Bloch 的 Effective Java 第二版 目前我在第 22 项 它描述了内部类和嵌套类 但我无法理解他这句话的意思 匿名类具有封闭实例当且仅当它们发生时 在非静态上下文中 有人能给我一个代码示例并解释它
  • Java 中的 ConcurrentHashMap 和 Hashtable [重复]

    这个问题在这里已经有答案了 Java 中的 ConcurrentHashMap 和 Hashtable 有什么区别 哪个对于线程应用程序更有效 ConcurrentHashMap 和 Hashtable 锁定机制 Hashtable属于Co
  • 覆盖 VK_Tab 焦点操作

    再会 我正在向 jTextField 添加 keyevent 侦听器 以便如果用户按下 Tab 键 插入符号位置将转到 jtextField 内文本的末尾 这是我的代码 private void jTextField1KeyPressed

随机推荐

  • BGP-LS 简介

    BGP LS xff08 BGP Link state xff09 汇总IGP协议收集的拓扑信息上送给上层控制器 产生原因 BGP LS是收集网络拓扑的一种新的方式 BGP LS特性产生前 xff0c 路由器使用IGP xff08 OSPF
  • ubuntu下vnc使用

    使用apt cache search vncserver命令搜索可以用来安装vncserver的软件包 xff0c 这里选用vnc4server安装vnc 2 使用apt get install vnc4server命令安装vncserve
  • 使用“反射”将 Java 中一种对象类型转换为另外一种类型

    将一种对象类型转换为另外一种类型的常用场景 场景如下 xff1a 一般后端是使用 MVC 三层架构进行分层 实体类 User 用于接收数据库中的数据 xff1b 表现层 UserVo 将数据传给前端 这中间免不了要将实体类转换为表现层中的对
  • Ubuntu18.04 vnc灰屏问题

    vnc安装完以后 xff0c 用客户端登录发现只有5901端口可用 xff0c 但是其他端口登录上去以后都是灰屏的 查找了一下 xff0c 需要修改配置文件 vnc xstartup为如下内容 xff1a bin bash export d
  • 安装docker

    1 查看docker安装目录 whereis docker docker usr bin docker etc docker usr libexec docker usr share man man1 docker 1 gz 2 查询运行文
  • 关于PiBOT使用的一些问题汇总--ing

    xff1a 多机通讯是按照教程设置环境变量ROS MASTER URI 初始化 pibot init env sh xff0c 使用rostopic已经能够查看 xff0c 但是主机PC无法启动launch 原因 xff1a 个人测试是需要
  • ubuntu 19.10系统解决E: 仓库 “http://ppa.launchpad.net/webupd8team/java/ubuntu eoan Release” 没有 Release 文件。

    在终端换源后遇到E 仓库 http ppa launchpad net webupd8team java ubuntu eoan Release 没有 Release 文件 问题 解决方法 xff1a 将对应的ppa删除即可 第一步 xff
  • 使用org-mode生成晨检报告

    原文地址 https lujun9972 github io blog 2020 04 10 使用org mode生成晨检报告 index html 我们设置了每天8点多自动进行调用一次晨检脚本 xff0c 该脚本会将检查的一些数据存入本地
  • 使用Pi-hole屏蔽广告

    原文地址 https www lujun9972 win blog 2020 12 05 使用pi hole屏蔽广告 index html 目录 获取Pi的对外IP地址安装Pi hole配置DNS配置拦截域名 获取Pi的对外IP地址 我们一
  • 笑话理解之Mature

    原文地址 https www lujun9972 win blog 2020 12 09 笑话理解之mature index html 目录 The difference between government bonds and men T
  • 笑话理解之Hearing

    原文地址 https www lujun9972 win blog 2020 12 09 笑话理解之hearing index html 目录 The Hearing Problem The Hearing Problem In a chu
  • Emacs 作为 MPD 客户端

    原文地址 https www lujun9972 win blog 2022 06 26 emacs 作为 mpd 客户端 index html 今天才知道 xff0c Emacs居然内置了一个 mpc el 可以将 Emacs 转换为 M
  • 编译SONiC交换机镜像(转,参考2)

    sonic buildimage 编译SONiC交换机镜像 描述 以下是关于如何为网络交换机构建 ONIE 兼容网络操作系统 xff08 NOS xff09 安装程序镜像的说明 xff0c 以及如何构建在NOS内运行的Docker镜像 请注
  • Emacs 作为 MPD 客户端

    原文地址 https www lujun9972 win blog 2022 06 26 emacs 作为 mpd 客户端 index html 今天才知道 xff0c Emacs居然内置了一个 mpc el 可以将 Emacs 转换为 M
  • 使用 calc 计算保险实际收益率

    原文地址 https www lujun9972 win blog 2022 08 10 使用 calc 计算保险实际收益率 index html 今天某银行的客户经理来推销一个 增额终身寿险 xff0c 号称是能锁定3 5 的收益率 具体
  • Emacs使用Deft管理笔记

    1 Deft介绍 Deft是一款写作和管理纯文本格式笔记的工具 通过它可以快速的查到或新建笔记 Deft的下载地址是Deft 也可以通过浏览或者拷贝git仓库 xff1a git clone git jblevins org git def
  • linux挂载samba文件系统的方法

    1 手工挂载 有两个命令可以用来手工挂载samba文件系统 xff0c 一个是mount xff0c 一个是smbmount 1 1 使用mount命令挂载 mount就是用于挂载文件系统的 xff0c SMB做为网络文件系统的一种 xff
  • DB2里面如何进行快速分页?就像mysql的limit之类的

    从百度知道里看到的 xff0c 记录下来以防忘记了 只查询前10行 fetch first 10 rows only SELECT SALE DATE SUM SALE MONEY AS SUM MONEY FROM SALE REPORT
  • linux时间与Windows时间不一致的解决

    转载至http goodluck1982 blog sohu com 138950694 html 一 首先要弄清几个概念 xff1a 1 系统时间 与 硬件时间 系统时间 一般说来就是我们执行 date命令看到的时间 xff0c linu
  • java list中删除元素用remove()报错的fail-fast机制原理以及解决方案

    java list中删除元素用remove 报错的fail fast机制原理以及解决方案 现在有一个list 有6个元素 xff0c 值分别是1 5 5 8 5 10 xff0c 现需要删除值为5的元素 第一种 import java ut