ArrayList for遍历删除分析

一、案例

//案例一
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        for (String item : list) {
            if ("1".equals(item)) {
                list.remove(item);
            }
        }
    } //运行不报错


//案例二
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        for (String item : list) {
            if ("2".equals(item)) {
                list.remove(item);
            }
        }
    } //运行报错Exception in thread "main" java.util.ConcurrentModificationException



二、javap反编译后字节码分析

 

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #2                  // class java/util/ArrayList
         3: dup
         4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #4                  // String 1
        11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        16: pop
        17: aload_1
        18: ldc           #6                  // String 2
        20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        25: pop
        26: aload_1
        27: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        32: astore_2
        33: aload_2
        34: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        39: ifeq          72
        42: aload_2
        43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        48: checkcast     #10                 // class java/lang/String
        51: astore_3
        52: ldc           #6                  // String 2
        54: aload_3
        55: invokevirtual #11                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
        58: ifeq          69
        61: aload_1
        62: aload_3
        63: invokeinterface #12,  2           // InterfaceMethod java/util/List.remove:(Ljava/lang/Object;)Z
        68: pop
        69: goto          33
        72: return

21-25行:java编译器把for循环编译成List.iterator,然后通过Iterator.hasNext,Iterator.next遍历,然后checkcast指令String类型校验


三、源码分析

 

  • 调用ArrayList.iterator(),返回Iterator对象
  • 标记5是Iterator对象的remove(),标记6是ArrayList的remove()
  • cursor是Iterator当前指针,lastRet是Iterator上次遍历的指针,modCount是ArrayList的变更次数,当add(1),add(2),remove(1)时,modCount=3


案例一分析:

  1. add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
  2. Iterator.hasNext():返回true
  3. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
  4. equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=1,size=1
  5. Iterator.hasNext():返回false,退出循环

总结:根本就没有遍历第二个字符串“2”

案例二分析:

  1. add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
  2. Iterator.hasNext():返回true
  3. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
  4. equals=false:modCount=2,expectedModCount=2,cursor=1,size=2
  5. Iterator.hasNext():返回true
  6. Iterator.next():标记3的checkForComodification()校验成功,返回字符串“2”
  7. equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=2,size=1
  8. Iterator.hasNext():返回true
  9. Iterator.next():标记3的checkForComodification()校验失败,modCount != expectedModCount抛异常ConcurrentModificationException

总结

  1. ArrayList.remove()方法不会更新expectedModCount,cursor,只更改了原数组,size,modCount等数据,由于数据不一致导致校验失败。
  2. Iterator.remove()方法会更新原数组,size,modCount等数据。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值