对于JAVA中具有Lambda表达式的循环

Kic*_*ski -5 java foreach lambda java-8

为什么我使用下面的代码 IndexOutOfBoundsException

码:

    List<Integer> ints = Stream.of(21,22,32,42,52).collect(Collectors.toList());
    System.out.print("the list: ");
    ints.forEach((i) -> {
        System.out.print(ints.get(i-1) + " ");
    });
Run Code Online (Sandbox Code Playgroud)

我的错误堆栈:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 11, Size: 5
    at java.util.ArrayList.rangeCheck(ArrayList.java:638)
    at java.util.ArrayList.get(ArrayList.java:414)
    at Agent.lambda$main$1(Agent.java:33)
    at Agent$$Lambda$8/980546781.accept(Unknown Source)
    at java.util.ArrayList.forEach(ArrayList.java:1234)
    at Agent.main(Agent.java:32)
the list: Java Result: 1
Run Code Online (Sandbox Code Playgroud)

但是当我将列表更改为一位数时,一切都很好

码:

    List<Integer> ints = Stream.of(2,8,7,4,3).collect(Collectors.toList());
    System.out.print("the list: ");
    ints.forEach((i) -> {
        System.out.print(ints.get(i-1) + " ");
    });
Run Code Online (Sandbox Code Playgroud)

输出:

2 8 7 4 3 
Run Code Online (Sandbox Code Playgroud)

Bri*_*etz 7

更简单:

String s = Stream.of(21,22,32,42,52)
                 .collect(Collectors.joining(" "));
Run Code Online (Sandbox Code Playgroud)


awk*_*ksp 6

我认为原因很清楚.

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});
Run Code Online (Sandbox Code Playgroud)

翻译大致到:

for (Integer i : ints) {
    System.out.println(ints.get(i - 1) + " ");
}
Run Code Online (Sandbox Code Playgroud)

这将导致IndexOutOfBoundsExceptions因为i引用每个列表的元素,并且每个元素 - 1将给出明显超出范围的索引.对于您的第一个示例,i21提供索引21 - 1 == 20,该索引超出您创建的列表的范围.

例:

List<Integer> ints = Stream.of(21,22,32,42,52).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

最终会这样结束

ints == [21, 22, 32, 42, 52]
Run Code Online (Sandbox Code Playgroud)

所以当你运行这个:

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});
Run Code Online (Sandbox Code Playgroud)

计算机获取第一个元素并尝试执行lambda的主体:

Execute System.out.print(ints.get(i-1) + " ");:
    First element is 21
    21 - 1 == 20
    ints.get(20) --> IndexOutOfBoundsException
Run Code Online (Sandbox Code Playgroud)

而对于你的第二个例子:

List<Integer> ints = Stream.of(2,8,7,4,3).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

ints == [2, 8, 7, 4, 3]
Run Code Online (Sandbox Code Playgroud)

所以当你运行这个:

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});
Run Code Online (Sandbox Code Playgroud)

计算机遍历元素并尝试执行lambda的主体:

Execute System.out.print(ints.get(i-1) + " ");:
    First element is 2
    2 - 1 == 1
    ints.get(1) --> 8
    Print 8
Execute System.out.print(ints.get(i-1) + " ");:
    Second element is 8
    8 - 1 == 7
    ints.get(7) --> IndexOutOfBoundsException
Run Code Online (Sandbox Code Playgroud)

显然,你的第二个例子中的代码并不是你实际拥有的代码.我怀疑你实际拥有的代码是:

List<Integer> ints = Stream.of(2,8,7,4,3).collect(Collectors.toList());
System.out.print("the list: ");
ints.forEach((i) -> {
    System.out.print(i + " ");
                     ^^^^^^^ <-- this is different
});
Run Code Online (Sandbox Code Playgroud)

这与你发布的完全不同.

  • @kick如果你有一个`[1,2,3,4]`的列表,你从每个中减去一个,你得到`[0,1,2,3]`.如果你然后使用这些作为第一个列表的索引,你得到值`[1,2,3,4]`.但是如果你有一个列表`[7,8,9,10]`,你从每个中减去一个,那么`[6,7,8,9]`然后使用那些作为索引,你会得到一个索引因为`[7,8,9,10]`中的索引7中没有元素,因此为边界. (4认同)
  • @KickButtowski你不明白我在说什么.你正在获取列表的*元素*并将它们用作*indices*.巧合的是,特定列表的元素恰好是有效的索引,而*作为接受的答案指出*,只要你的元素太大,你就会超出界限异常. (3认同)
  • @KickButtowski是的,你应该理解我们刚刚在答案中解释的内容.**lambda中的`i`是底层`List`中的每个连续元素.** (3认同)
  • @KickButtowski由于列表中元素的价值,这只是巧合...... (2认同)
  • @KickButtowski您是否在问题中尝试了两段代码?因为这两个都会抛出异常.你上一个问题*中的代码*发生*是正常的,但正如接受的答案所指出的那样,错误的值会抛出异常 (2认同)

Sot*_*lis 5

forEach贾瓦多克

对Iterable的每个元素执行给定操作,直到处理完所有元素或操作抛出异常为止.

所以i

(i) -> {System.out.print(ints.get(i-1) + " ");}
Run Code Online (Sandbox Code Playgroud)

是每个元素List.如果减去1的任何元素大于或等于5(大小List),则尝试获取超出范围的元素.