先看看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); 有参数问题,无法绕过。