collection容器Iterator接口快速失败代码演示

本文深入探讨了HashSet集合的遍历方法及Iterator的工作原理,重点介绍了如何利用Iterator遍历HashSet并安全地移除元素,同时讨论了并发修改异常的触发条件及其解决方案。


先看看Iterator的范围 是所有collection容器,他的实现类都分别对这个iterator进行了单独的实现。

这次以HashSet集合为例:

public static void main(String[] args) {
//标准的set集合遍历
Set<String> set=new HashSet<String>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
//传统的Iterator遍历方式
Iterator<String> it = set.iterator();
   	 while(it.hasNext()){
       	  System.out.println(it.next());
    	}
}

这是最常见的遍历方式 
输出的是竖着的 abcd


去看iterator的源代码 里面方法还有remove()方法  这个可以删除当前的节点。

于是代码可以写成:

Iterator<String> it = set.iterator();
   while(it.hasNext()){
       	System.out.println(it.next());
        it.remove();
    }
System.out.println(set.size());
使用方式 一般是在这里  最后set.size()应该是为0


这是hashset等几乎所有实现类对 iterator的统一解释。
突出的就是这个异常在异步等操作时候的问题。

那么就去触发这个remove()以外方法修改的bug。

  while (it.hasNext()) {
	System.out.println(1);
	String str=it.next();
	//这里用set的remove(String)方法和递归来去除节点
	System.out.println(set.remove(str));
  }

1
true
1
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
	at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
	at com.cyk.itera.SetIteErr1.main(SetIteErr1.java:23)
在第二次循环String str=it.next(); 触发此异常。

可以理解成 iterator就是一个链表(实际我不知道),

it.next()就是剪去节点,并把后面的和节点前面的链接起来,链表已经有效。
这里是没有链接导致报错。

有一个方法是递归,不再进行第二次it.next()

public static void main(String[] args) {
		// 标准的set集合遍历
		Set<String> set = new HashSet<String>();
		set.add("a");
		set.add("b");
		set.add("c");
		set.add("d");
		// 传统的Iterator遍历方式
		set.addAll(myIterator(set));
		System.out.println(set.size());
		
	}

	private static Collection<? extends String> myIterator(Set<String> set) {
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			String str=it.next();
			//这里用set的remove(String)方法和递归来去除节点
			System.out.println(set.remove(str));
			myIterator(set);
			break;
		}
		return set;
	}
这个代码 就是曲线救国 在不知道it的remove方法时候  实现的  显然 递归浪费了不少栈空间。

一般情况下还是可以用的。

但这个是用很大风险的,在一定数据量之后,而且,不是偶然,风险就在:

set.remove(str);

小数据量 绝对没错的

但当递归数据量达到一定程度,压栈也没有满,会出现 remove(str)方法 返回boolean值为false的情况。

这样每次都不能移除这个点,进入递归的无限死循环,很快导致Stack Overflow。

是21^2。但我另一个数据在60^2时候,会在第64个外界大循环 时候出现无限的set.remove(String)报false的问题。

以上只是表示运算数据量,不用理解我说的是什么。

就是说  java  在一定量级时候,可能出现那种,从一个set数据中获取一个String,  然后底层.equlse()方法  发现 不认识它了。

这个问题 不是逻辑和语法上的问题 只是在运行时候 某种特定环境会出发  至少我这种递归深度压栈 并且 String的字符长度比较大的时候
这个格式在我那个代码中是100%发生的 哪怕你删了出错数据 他会换下一条数据报错。

这应该就是底层 问题了 可能是那种越界了  我没有解决 
最好的办法就是:不去判断直接删除 。迭代器的it.remove();


但你不用这个方法的话 就会面临 boolean remove(Object o);  有参数问题,无法绕过。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值