iterator详解

本文源码基于 jdk8

fast-fail 机制s分析

什么是 fast-fail ?
让我们用代码的形式来理解很清晰。

  • 运行这段代码
public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
        list.add(1);list.add(2);list.add(4);
        ListIterator iterator = list.listIterator();
        iterator.add(4);
        System.out.println(list);
    	//list.add(3);
        while (iterator.hasNext()){//迭代器的迭代方法
            System.out.println(iterator.next());
        }
}
  • 控制台输出
[1, 2, 4]
1
2
4
  • 去掉注释后 ~~//~~list.add(3);
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966)
	at java.util.LinkedList$ListItr.next(LinkedList.java:888)
	at Test.main(Test.java:14)

okay,看完样例后,我们就清楚这个 fast-fail 是啥意思了,那么这是为什么呢,跟我一起走进源码看看。
这是检查是否更改方法所抛出的异常,往上翻发现listItr中其他的方法基本都调用了这个方法.

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

modCount是从父类AbstractList中继承的,查看源码注释

The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.

modCount记录了导致结构变化的操作次数

  • 为什么不能保证fail-fast呢?

因为若是并发操作结构变化后modcount仍未修改,然而此时迭代器已经读入modecount,那么就不会抛出异常,也就是说这个机制就失效了。

样例:

public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);list.add(2);list.add(4);
        Iterator iterator = list.iterator();
        System.out.println(list);
        new Thread(()->{//添加新线程执行add
            list.add(4);
        }).start();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

控制台输出:

[1, 2, 4]
1
2
4

Iterator和foreach循环有什么关系?

//代码
public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);list.add(2);list.add(4);
        for (Integer integer : list) {
            System.out.println(integer);
        }
}

IDEA(安装插件后)查看字节码**【foreach循环片段】**

34 pop
35 aload_1
36 invokevirtual #6 <java/util/LinkedList.iterator>
39 astore_2
40 aload_2
41 invokeinterface #7 <java/util/Iterator.hasNext> count 1
46 ifeq 69 (+23)
49 aload_2
50 invokeinterface #8 <java/util/Iterator.next> count 1
55 checkcast #9 <java/lang/Integer>
58 astore_3
59 getstatic #10 <java/lang/System.out>
62 aload_3
63 invokevirtual #11 <java/io/PrintStream.println>
66 goto 40 (-26)
69 return

结论:foreach循环实际上是调用(动态链接?//TODO)迭代器的迭代方法,所以foreach过程中不允许其他修改实例的操作。(参考fast-fail)

forEach又是什么鬼??

foreach(加强循环)是一个语法结构,实际是用迭代器(Iterator)的迭代方法。

forEach是Iterable接口的default方法(以实现方法)

Iterable是所有拥有Iterator需要实现的接口

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);	
        }
}

okay,大家一看到这个循环就懂了,不过是包装了消费者模式的皮而已_

写段代码来展示一下它的威力吧

public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);list.add(2);list.add(4);
        list.forEach((str)->{//函数式匿名类
            System.out.println(str);
        });
}
//控制台输出
1
2
4

看看它的部分字节码?(用idea来查看bytecode可以展示出模式的作用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Y3nom8I-1587944944858)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200421181509466.png)]

结论:forEach 仍然是使用迭代器的迭代方法,那么当然也不能做修改实例结构的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值