
先看代码:
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); } } 我也看不出端倪啊。 我搞明白了会更贴的。
1 shazh520 OP 这个格式我也是醉了,调了四五次才勉强可以看。 |
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/ |
3 lhx2008 2018-06-22 22:26:38 +08:00 |
5 shazh520 OP 运行结果就像下面这样: [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] |
6 zpxshl 2018-06-22 22:29:03 +08:00 via Android 输出结果是什么,我验证下... |
7 shazh520 OP 不对,上面贴那个运行结果是我后面改过代码的结果。 |
8 shazh520 OP 运行结果是这样(这个绝对没问题): [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] |
9 hcymk2 2018-06-22 22:35:39 +08:00 for (Integer t : test) { System.out.println(t); test.remove(t); break; } |
10 zpxshl 2018-06-22 22:38:03 +08:00 via Android 你这代码和反编译代码确定是对应的吗?怎么感觉反编译的代码少了个循环? |
11 lhx2008 2018-06-22 22:38:29 +08:00 @shazh520 蛋疼,你开始代码太乱没看。 你打断点看下就知道了,remove 不是删除那个元素,而是删除那个下标,所以一直在删除 第 1 个 (从 0 开始)元素,然后你 i 会执行 50 次,就是做了 50 次删除第一个元素。唉,还反编译 |
12 zpxshl 2018-06-22 22:39:50 +08:00 via Android 好吧我错了,少看到个 break... |
14 lonenol 2018-06-22 22:41:56 +08:00 第一次删了 0,变成 1-99 然后每次都是 remove(1),删第二个元素,保留了 1 就变成你看到的那样了。。 |
15 shazh520 OP @lhx2008 按照这个说法那最后应该是留下了 0 而不是留下 1 没有删除。循环的第一次执行正确的删除了下标为 0 的元素“ 0 ”,但是后面的每次执行为什么就都在删除下标为 1 的元素了呢? |
16 shazh520 OP @lonenol 我就是搞不明白为啥后面都是删除第二个元素了。 这个太诡异了嘛,没有规律啊。第一次为啥特殊勒,大佬? |
17 lhx2008 2018-06-22 22:48:10 +08:00 via Android @shazh520 第一次是 0123,第一个数就是 0,当然就把 0 删掉了,后面变成 123,第一个数是 1,就一直删第一个数,1 是第 0 个数 |
18 zpxshl 2018-06-22 22:48:17 +08:00 via Android @shazh520 你的 list 从 0 开始,第一次循环删掉下标 0,正好值为 0。 list 变成 1 开始。 第二次-n 次循环,每次都是删掉下标为 1 的数,就是删掉 2,3,4,5... |
19 qusthuang 2018-06-22 22:53:14 +08:00 remove(Integer ) 和 remove(int),看下 jdk 实现就知道了 |
20 shazh520 OP @lhx2008 [手动笑哭表情] 大佬,我大体猜到你表达的意思了,你前半句中的第一个数指的是下标 0,后半句中的第一个数指的是下标 1 是吧。 但是我就是想问,为啥第一次删除下标 0,第二次删除下标 1,第三次删除下标 1,...,没规律啊。 |
22 lhx2008 2018-06-22 22:55:26 +08:00 via Android |
25 shazh520 OP 如果代码是这样结果就完全不一样了,就像是 @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); } } |