为啥在 lambda 中使用 ++i 而不是 i++

Posted

技术标签:

【中文标题】为啥在 lambda 中使用 ++i 而不是 i++【英文标题】:why using ++i but not i++ in lambda为什么在 lambda 中使用 ++i 而不是 i++ 【发布时间】:2018-01-09 00:52:07 【问题描述】:

我碰巧知道,在下面的表达式中,使用i++会导致无限流,i总是0。我很困惑是因为我认为i++没有使用返回值,即使这样,它不应该中断i之后的增量。

IntStream.iterate(0, i-> i<10, i-> ++i).forEach(....)

【问题讨论】:

我对java9不太熟悉,但IntStream.iterate(0, i-&gt; i&lt;10, i-&gt; i+1).forEach(....)不应该更自然吗?你有任何理由使用i++++i 吗? Java: Prefix/postfix of increment/decrement operators?的可能重复 @ymonad i+1 也可以。我想知道为什么i++ 没有。现在很清楚了。 i++在函数中运行,函数返回值赋值给i... 【参考方案1】:

通过检查 Java 9 的 API IntStream : http://download.java.net/java/jdk9/docs/api/java/util/stream/IntStream.html#iterate-int-java.util.function.IntPredicate-java.util.function.IntUnaryOperator-

最后一个函数(在您的情况下为i -&gt; ++i)是确定下一个值是什么。

如果你输入i-&gt;i++,鉴于它是一个后缀递增运算符,i++ 在递增之前计算为i。这意味着它始终返回相同的值(在您的情况下为种子 0)。因此,它就像您输入i -&gt; i 一样工作。请注意,Java 中的参数是按值传递的。因此,您在 lambda 中的增量不会影响调用者。

因此,hasNext 谓词(第二个参数,在您的情况下为 i-&gt;i&lt;10)始终评估为真,因此为您提供了无限的全零流。

【讨论】:

i -&gt; i++ 中有一个非常混乱的序列。 1)i 分配给i,2)i 加 1。但无论哪个先到,除非 i 永远不会加 1(就像 ++ 运算符总是这样做),i不应该永远为 0。这是我不明白的部分。 第三个参数是一个函数,用于告诉IntStream 下一个值是什么(给定前一个值)。不管你在函数中做了什么,只要你返回了某个值,那个返回的值就是下一个要使用的值。 换一种方式,i -&gt; i++ 在你的情况下就像i -&gt; int temp = i; i = i + 1; return temp。给定参数是按值传递的,您的 i=i+1 对调用者没有影响。因此下一个值总是与原始值相同。 啊,我明白了【参考方案2】:

您可以使用限制并按照您的建议做:

IntStream.iterate(0, i -> i++).limit(10).forEach(....)

这也有帮助:

Java Incremental operator query (++i and i++)

【讨论】:

但仍然想知道为什么i++ 没有增加i。这挑战了我的“常识”。 @Tina Java 中的参数是按值传递的。我相信你还没有开发出 Java 的常识。 @Tiina 希望我的更新和阿德里安能帮助你找到答案 @DamianLattenero 更新使答案变得更糟。这个问题是关于Java的,Java中没有运算符重载。 @AdrianShum 关于“常识”请参阅我在您的回答中留下的第一条评论...【参考方案3】:

请记住,lambda 表达式是一种将函数式接口(只有一个抽象方法的接口)实现表示为匿名函数的方式。

在您的 iterate() 方法中,第三个参数是 IntUnaryOperator。这有一个抽象方法 applyAsInt(),它接受一个 int 作为参数并返回一个 int。如果您将 Lambda 表达式重写为等效的匿名内部类(您可以在这里完全合法地使用它),您会得到:

IntStream.iterate(0, i -> i < 10, new IntUnaryOperator() 
  @Override
  public int applyAsInt(int i) 
    return i++;
  
)
.forEach(System.out::println);

在这种情况下,很明显,您要在 i 递增之前返回它的值(后缀运算符)。 i 的初始值为零,因此您将获得无限的零流。如果您将 applyAsInt() 方法更改为使用前缀运算符 ++i,则 i 的值将在返回之前递增,从而为您提供所需的结果 1, 2 ... 9

【讨论】:

以上是关于为啥在 lambda 中使用 ++i 而不是 i++的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 C for 循环的条件中使用表达式而不是常量?

为啥在 ASP.NET MVC 中使用 lambdas 而不是反射?

c# 在 Lambda 表达式中声明变量

为啥在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?

为啥我应该使用 continue 而不是空的 if 语句? [关闭]

为啥 std::apply 可以调用 lambda 而不是等效的模板函数?