我使用IntStream和forEach创建整数列表的方法有什么问题?

Kor*_*gay 8 java java-8 java-stream

我的天真代码是:

class ${
    public static void main(String[] _) {
        final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> i++).limit(5).forEach(val -> ints.add(val));
        System.out.println(ints);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的期望是在控制台中看到以下内容:

[0, 1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

但实际是:

[0, 0, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)

这可能是非常简单的事情,但我错过了什么?

Joh*_*ica 35

i++具有增值i 之前的值.您需要使用前缀运算符.

IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));
Run Code Online (Sandbox Code Playgroud)

实际上,不要这样做.没有理由变异i,它被简单地扔掉了.使用副作用免费版.毕竟,这就是功能编程背后的全部理念:避免副作用.

IntStream.iterate(0, i -> i + 1).limit(5).forEach(val -> ints.add(val));
Run Code Online (Sandbox Code Playgroud)

对于连续整数流的特定情况,您可以替换iteratelimit使用range:

IntStream.range(0, 5).forEach(val -> ints.add(val));
Run Code Online (Sandbox Code Playgroud)

最后,将流收集到列表中而不是添加值也会更好forEach.它直接表达了创建列表的意图,这又避免了副作用.

List<Integer> ints = IntStream.range(0, 5).boxed().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)


Nam*_*man 5

您传递值时使用的是后缀i++,而不是前缀.更改为以下内容将为您提供预期的输出:++iforEach

IntStream.iterate(0, i -> i + 1).limit(5).forEach(ints::add);
Run Code Online (Sandbox Code Playgroud)

一边,迭代和组合与Java9 +限制的替代方法是使用IntStream.iterate具有IntPredicate如:

IntStream.iterate(0, i -> i < 5, i -> i + 1).forEach(ints::add);
Run Code Online (Sandbox Code Playgroud)

  • 好的,你提到了Java9 +的`IntStream.iterate`重载版本 (2认同)

fla*_*kes 3

您需要返回增加的值。您对局部变量进行后缀增量并返回非增量值。使用++ii++

final List<Integer> ints = new ArrayList<>();
IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));
System.out.println(ints);
Run Code Online (Sandbox Code Playgroud)

编辑请参阅 John Kugelman 关于以函数式编程时使用非变异操作的文章。使用i + 1将创建一个新的原语并且不会改变参数变量。

  • 不要使用任何会误导性地修改参数变量的构造。只需使用“i -&gt; i + 1”即可。 (22认同)