Java 集合框架之 ConcurrentModificationException

1、迭代器原理

        java 中提供了很多的集合类,不同集合类的数据结构不同,所以这些集合类的数据存储方式和遍历方式也应该不同,所以无法为所有集合类提供统一迭代器,只能提供一个接口。

       通过源码分析可以得知,集合对接口的实现在他们的具体实现类中,并且以私有内部类的方式体现。

2、ConcurrentModificationException

public class ConcurrentModificationExceptionDemo
{
	public static void main(String[] args)
	{
		Collection<String> c = new ArrayList<String>();
		c.add("Java");
		c.add("Android");
		c.add("HTML");
		c.add("C#");
		
                // 迭代器遍历集合
		Iterator<String> it = c.iterator();
		
		while(it.hasNext())
		{
			String str = it.next();
			
			if(str.equals("Java"))
			{
                                // 集合 add() 方法添加元素
				c.add("JavaEE");
			}
		}
	}
}

       在运行以上代码时,程序将会抛出 ConcurrentModificationException 异常(并发操作异常),这是因为代码中使用迭代器遍历集合过程中通过集合添加了元素

   (1) 概述

       当检测到对象的并发修改,但不允许这种修改时抛出该异常

   (2) 产生原因

       迭代器依赖于集合存在,在迭代时通过集合添加元素,但集合的改变并没有同步到迭代器,所以引发该异常。

   (3) 解决方法

       方式一:使用迭代器遍历,通过迭代器来修改元素(只使用于 List 实现类

public class ConcurrentModificationExceptionDemo
{
	public static void main(String[] args)
	{
		List<String> c = new ArrayList<String>();
		c.add("Java");
		c.add("Android");
		c.add("HTML");
		c.add("C#");
		
                // 使用迭代器遍历集合
		ListIterator<String> it = c.listIterator();
		
		while(it.hasNext())
		{
			String str = it.next();
			
			if(str.equals("Java"))
			{
				// 使用迭代器的 add() 添加元素
				it.add("JavaEE");
			}
		}
		
		System.out.println(c);
	}
}

       运行结果:

       方式二: 使用集合遍历,通过集合来修改元素

public class ConcurrentModificationExceptionDemo
{
	public static void main(String[] args)
	{
		List<String> c = new ArrayList<String>();
		c.add("Java");
		c.add("Android");
		c.add("HTML");
		c.add("C#");
		
		// 使用集合遍历
		for(int i = 0; i < c.size(); i++)
		{
			String str = c.get(i);
			
			if(str.equals("Java"))
			{
				// 使用集合 add() 方法添加元素
				c.add("JavaEE");
			}
		}
		
		System.out.println(c);
	}
}

        运行结果:

        注意:

        foreach 遍历其底层为迭代器,所以遍历时修改也会出现该异常。

        两种方式虽然都满足了需求,但是存在一些不同之处:方式一插入新元素的位置在当前迭代位置的后面;而方式二插入新元素的位置在列表最后面。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会为你介绍一些Java集合框架的面试题及答案。 1. Java 集合框架包括哪些接口及其特点? Java集合框架包括以下接口: - Collection 接口:表示一组对象,它们可能是有序的或无序的,并且可以包含重复的元素。 - List 接口:继承自 Collection 接口,表示有序集合,并且允许重复元素。 - Set 接口:继承自 Collection 接口,表示无序集合,并且不允许重复元素。 - Map 接口:表示一组键值对,其中键是唯一的,但值可以重复。 2. ArrayList 和 LinkedList 的区别是什么? ArrayList 和 LinkedList 都实现了 List 接口,但它们的实现方式不同。ArrayList 是基于动态数组实现的,它的元素可以直接通过下标访问,因此查找元素的效率比较高。LinkedList 是基于双向链表实现的,它的元素不能直接通过下标访问,但在插入和删除元素时效率比 ArrayList 更高。 3. HashMap 和 HashTable 的区别是什么? HashMap 和 HashTable 都实现了 Map 接口,但它们的实现方式不同。HashMap 是非线程安全的,它允许存储空键和空值。HashTable 是线程安全的,但它不允许存储空键或空值。另外,HashMap 的迭代器是 fail-fast 的(在迭代器中修改了 map 的结构会抛出 ConcurrentModificationException),而 HashTable 的迭代器不是 fail-fast 的。 4. HashSet 和 TreeSet 的区别是什么? HashSet 和 TreeSet 都实现了 Set 接口,但它们的实现方式不同。HashSet 是基于 HashMap 实现的,它不保证元素的顺序,也不允许重复元素。TreeSet 是基于 TreeMap 实现的,它保证元素是有序的,并且不允许重复元素。 5. 如何选择合适的集合? 选择集合要根据具体的需求来决定。如果需要有序集合,并且需要频繁地在集合中间插入或删除元素,可以选择 LinkedList。如果需要有序集合,并且需要频繁地访问集合中的元素,可以选择 ArrayList。如果需要无序集合,并且需要快速地查找元素,可以选择 HashSet。如果需要有序集合,并且需要快速地查找元素,可以选择 TreeSet。如果需要存储键值对,并且需要根据键快速地查找值,可以选择 HashMap。如果需要存储键值对,并且需要有序地遍历键值对,可以选择 TreeMap。如果需要线程安全的集合,可以选择 HashTable 或 ConcurrentHashMap。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值