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

时间:2014-06-26 18:47:29

标签: 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) + " ");
    });

我的错误堆栈:

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

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

代码:

    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) + " ");
    });

输出:

2 8 7 4 3 

4 个答案:

答案 0 :(得分:7)

更简单:

String s = Stream.of(21,22,32,42,52)
                 .collect(Collectors.joining(" "));

答案 1 :(得分:6)

我认为原因非常清楚。

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});

大致转换为:

for (Integer i : ints) {
    System.out.println(ints.get(i - 1) + " ");
}

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

示例:

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

将以

结束
ints == [21, 22, 32, 42, 52]

所以当你运行它时:

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});

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

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

对于你的第二个例子:

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

变为

ints == [2, 8, 7, 4, 3]

所以当你运行它时:

ints.forEach((i) -> {
    System.out.print(ints.get(i-1) + " ");
});

计算机浏览元素并尝试执行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

显然,你的第二个例子中的代码是而不是你实际拥有的东西。我怀疑你实际拥有的代码是:

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
});

这与你发布的完全不同。

答案 2 :(得分:5)

forEach javadoc

  

对Iterable的每个元素执行给定的操作,直到全部   元素已被处理或操作引发异常。

所以<{p>}中的i

(i) -> {System.out.print(ints.get(i-1) + " ");}

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

答案 3 :(得分:3)

你太过分了。你想要的是

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 + " ");
});
forEach中的

i不是循环计数器,而是项目本身。因此i将采用值2,8,7,4,3,而第二次迭代ints.get (8-1)将超出范围。