关于 Java foreach 循环删除多个元素的有趣问题(不是抛异常哦) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
shazh520
V2EX    Java

关于 Java foreach 循环删除多个元素的有趣问题(不是抛异常哦)

  •  2
     
  •   shazh520 2018-06-22 22:19:30 +08:00 4142 次点击
    这是一个创建于 2717 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先看代码:

     import java.util.ArrayList; import java.util.List; public class ForeachTest { public static void main(String[] args) { List<Integer> tst = new ArrayList<>(); for (int i = 0; i < 100; i++) { test.add(i); } System.out.println(test); for (int i = 0; i < 50; i++) { for (int t : test) { System.out.println(t); test.remove(t); break; } } System.out.println(test); } } 

    完整的代码在上面,各位大佬知道为什么会出现那种运行结果吗?如果知道请指点一二,推荐个阅读资料也行,不胜感激。我 Google 了一晚上只找到了一些关于异常的资料,反编译了以后代码是这样的

     import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ForeachTest { public static void main(String[] paramArrayOfString) { ArrayList localArrayList = new ArrayList(); for (int i = 0; i < 100; i++) { localArrayList.add(Integer.valueOf(i)); } System.out.println(localArrayList); for (i = 0; i < 50; i++) { Iterator localIterator = localArrayList.iterator(); if (localIterator.hasNext()) { int j = ((Integer)localIterator.next()).intValue(); System.out.println(j); localArrayList.remove(j); } } System.out.println(localArrayList); } } 

    我也看不出端倪啊。 我搞明白了会更贴的。

    25 条回复    2018-06-24 12:50:45 +08:00
    shazh520
        1
    shazh520  
    OP
       2018-06-22 22:24:45 +08:00
    这个格式我也是醉了,调了四五次才勉强可以看。
    lhx2008
        2
    lhx2008  
       2018-06-22 22:24:59 +08:00
    The iterators returned by this class ’ s iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator ’ s own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

    from:
    http://jtuts.com/2016/02/26/remove-element-from-alist-during-iteration-in-java/
    shazh520
        4
    shazh520  
    OP
       2018-06-22 22:26:47 +08:00
    @lhx2008 不是抛异常,是删除元素的位置有点诡异。等我贴运行结果
    shazh520
        5
    shazh520  
    OP
       2018-06-22 22:28:41 +08:00
    运行结果就像下面这样:

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 9, 99]
    0
    1
    2
    1
    2
    ...//省略了四十行左右
    2
    1
    2
    1
    2
    [1, 2, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
    zpxshl
        6
    zpxshl  
       2018-06-22 22:29:03 +08:00 via Android
    输出结果是什么,我验证下...
    shazh520
        7
    shazh520  
    OP
       2018-06-22 22:32:55 +08:00
    不对,上面贴那个运行结果是我后面改过代码的结果。
    shazh520
        8
    shazh520  
    OP
       2018-06-22 22:34:16 +08:00
    运行结果是这样(这个绝对没问题):

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
    0
    1
    1
    ...
    1
    1
    1
    [1, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
    hcymk2
        9
    hcymk2  
       2018-06-22 22:35:39 +08:00
    for (Integer t : test) {
    System.out.println(t);

    test.remove(t);
    break;
    }
    zpxshl
        10
    zpxshl  
       2018-06-22 22:38:03 +08:00 via Android
    你这代码和反编译代码确定是对应的吗?怎么感觉反编译的代码少了个循环?
    lhx2008
        11
    lhx2008  
       2018-06-22 22:38:29 +08:00
    @shazh520 蛋疼,你开始代码太乱没看。
    你打断点看下就知道了,remove 不是删除那个元素,而是删除那个下标,所以一直在删除 第 1 个 (从 0 开始)元素,然后你 i 会执行 50 次,就是做了 50 次删除第一个元素。唉,还反编译
    zpxshl
        12
    zpxshl  
       2018-06-22 22:39:50 +08:00 via Android
    好吧我错了,少看到个 break...
    shazh520
        13
    shazh520  
    OP
       2018-06-22 22:41:07 +08:00
    @zpxshl 编译器优化了那个循环,是对应的
    lonenol
        14
    lonenol  
       2018-06-22 22:41:56 +08:00
    第一次删了 0,变成 1-99
    然后每次都是 remove(1),删第二个元素,保留了 1
    就变成你看到的那样了。。
    shazh520
        15
    shazh520  
    OP
       2018-06-22 22:45:37 +08:00
    @lhx2008 按照这个说法那最后应该是留下了 0 而不是留下 1 没有删除。循环的第一次执行正确的删除了下标为 0 的元素“ 0 ”,但是后面的每次执行为什么就都在删除下标为 1 的元素了呢?
    shazh520
        16
    shazh520  
    OP
       2018-06-22 22:47:13 +08:00
    @lonenol 我就是搞不明白为啥后面都是删除第二个元素了。 这个太诡异了嘛,没有规律啊。第一次为啥特殊勒,大佬?
    lhx2008
        17
    lhx2008  
       2018-06-22 22:48:10 +08:00 via Android
    @shazh520 第一次是 0123,第一个数就是 0,当然就把 0 删掉了,后面变成 123,第一个数是 1,就一直删第一个数,1 是第 0 个数
    zpxshl
        18
    zpxshl  
       2018-06-22 22:48:17 +08:00 via Android   1
    @shazh520 你的 list 从 0 开始,第一次循环删掉下标 0,正好值为 0。 list 变成 1 开始。 第二次-n 次循环,每次都是删掉下标为 1 的数,就是删掉 2,3,4,5...
    qusthuang
        19
    qusthuang  
       2018-06-22 22:53:14 +08:00   1
    remove(Integer ) 和 remove(int),看下 jdk 实现就知道了
    shazh520
        20
    shazh520  
    OP
       2018-06-22 22:53:27 +08:00
    @lhx2008 [手动笑哭表情] 大佬,我大体猜到你表达的意思了,你前半句中的第一个数指的是下标 0,后半句中的第一个数指的是下标 1 是吧。 但是我就是想问,为啥第一次删除下标 0,第二次删除下标 1,第三次删除下标 1,...,没规律啊。
    shazh520
        21
    shazh520  
    OP
       2018-06-22 22:54:52 +08:00
    @qusthuang
    @zpxshl 大佬,我结合你们两个的回答我找到答案了 哈哈 谢谢谢谢
    lhx2008
        22
    lhx2008  
       2018-06-22 22:55:26 +08:00 via Android   1
    @shazh520 你的代码可以简写成
    50 次循环
    renove(test[0])
    第一次 test[0] 是 0
    后面都是 1
    VoidChen
        23
    VoidChen  
       2018-06-23 10:52:46 +08:00
    @shazh520 其实 @lhx2008 早就说出了答案了,你还一直没看懂。。。
    shazh520
        24
    shazh520  
    OP
       2018-06-24 12:48:21 +08:00
    @VoidChen 对的 哈哈
    shazh520
        25
    shazh520  
    OP
       2018-06-24 12:50:45 +08:00
    如果代码是这样结果就完全不一样了,就像是 @qusthuang 说的那样,删除对象和下标的问题。
    package com.sunhao.seckill;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;

    import java.util.ArrayList;
    import java.util.List;

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SeckillApplicationTests {

    public static void main(String[] args) {
    List<Integer> integerList = new ArrayList<>();

    for (int i = 0; i < 100; i++) {
    integerList.add(i);
    }

    System.out.println(integerList);

    for (int i = 0; i < 50; i++) {
    for (Integer integer :
    integerList) {
    System.out.println(integer);
    integerList.remove(integer);
    break;
    }
    }

    System.out.println(integerList);
    }

    }
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2816 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 13:04 PVG 21:04 LAX 05:04 JFK 08:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86