为啥在 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-> i<10, i-> 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 -> ++i
)是确定下一个值是什么。
如果你输入i->i++
,鉴于它是一个后缀递增运算符,i++
在递增之前计算为i
。这意味着它始终返回相同的值(在您的情况下为种子 0
)。因此,它就像您输入i -> i
一样工作。请注意,Java 中的参数是按值传递的。因此,您在 lambda 中的增量不会影响调用者。
因此,hasNext
谓词(第二个参数,在您的情况下为 i->i<10
)始终评估为真,因此为您提供了无限的全零流。
【讨论】:
i -> i++
中有一个非常混乱的序列。 1)i
分配给i
,2)i
加 1。但无论哪个先到,除非 i
永远不会加 1(就像 ++
运算符总是这样做),i
不应该永远为 0。这是我不明白的部分。
第三个参数是一个函数,用于告诉IntStream
下一个值是什么(给定前一个值)。不管你在函数中做了什么,只要你返回了某个值,那个返回的值就是下一个要使用的值。
换一种方式,i -> i++
在你的情况下就像i -> 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++的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 ASP.NET MVC 中使用 lambdas 而不是反射?
为啥在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?