嵌套BiFunction的深度(或限制,如果有的话)是多少

Nir*_*mal 4 java functional-programming java-8

我一直在玩BiFunction(java.util.function).我举了一些例子,我有一个问题.

是否可以使用BiFunction嵌套操作的次数有限制?是否像add(a, b) 想要的那样多次嵌套假设方法一样简单?

例如三个嵌套 theFunction.apply()

public static int methodContainingMethod
         (int a, int b, int c, BiFunction<Integer, Integer, Integer> theFunction) {
    return theFunction.apply(theFunction.apply(theFunction.apply(a,b),c),c),c);
}
Run Code Online (Sandbox Code Playgroud)

四个嵌套 theFunction.apply()

return
  theFunction.apply(theFunction.apply(theFunction.apply(theFunction.apply(a,b),c),c),c),c);
Run Code Online (Sandbox Code Playgroud)

嵌套的数量可以继续,我测试嵌套功能超过十次.

我没有关于需要多少嵌套的确切要求......但我很好奇这样可以做多少嵌套?

Hol*_*ger 6

首先,这不是以BiFunction任何方式具体的.所以你基本上都在问,嵌套方法调用有多深,简单的答案是Java编程语言本身没有指定限制.

存在可能限制数量的技术限制,但这些限制是技术限制,而不是通过规范限制.当技术发展而不改变规范时,它们可能会被解除.

正如Alain O'Dea所解释的,如果异常处理程序应该覆盖最后一条指令,则方法的代码大小限制为65535字节或65534字节.此代码大小支持的嵌套方法调用量取决于某些因素.例如,您正在使用interface和接口方法调用使用比具体类方法调用(调用虚拟指令)更多的字节,而且,您正在使用BiFunction<Integer, Integer, Integer>而不是直接,IntBinaryOperator因此每次调用都涉及装箱int需要额外代码的值.

但无论如何,还有另一个技术限制,即编译器实现.当尝试使用更高的嵌套计数编译您的示例时,javac从以1500嵌套调用的stackoverflow结束的命令行运行,而Netbeans(使用相同的编译器代码javac)设法在IDE开始表现出奇怪的行为之前编译2000嵌套调用(我猜,它不能很好地处理编译器/语法高亮显示器的堆栈溢出).

这表明IDE在表达式解析之前具有更高的堆栈大小或环境设置中的其他差异影响了初始堆栈深度.这导致了在实践中没有硬性限制的结论.你可能能够编写一个编译器能够编译而没有问题的代码,而另一个编译器可以解决这个问题.

毕竟,相当于你问题的代码可以写成:

public static int methodContainingMethod(
    int a, int b, int c, BiFunction<Integer, Integer, Integer> theFunction) {

    int value = theFunction.apply(a, b);
    for(int i=0; i<asDeepAsYouWannaGo; i++)
        value=theFunction.apply(value, c);
    return value;
}
Run Code Online (Sandbox Code Playgroud)

虽然我认为,你的想法更像是:

public static int methodContainingMethod(
    IntBinaryOperator theFunction, int first, int second, int... rest) {

  int value = theFunction.applyAsInt(first, second);
  for(int next: rest) value=theFunction.applyAsInt(value, next);
  return value;
}
Run Code Online (Sandbox Code Playgroud)

要么

public static OptionalInt methodContainingMethod(
    IntBinaryOperator theFunction, int... arguments) {

  return IntStream.of(arguments).reduce(theFunction);
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案.这是一个很好的证明,编译器如何无法编译正确的,但由于特定于实现的原因的病理代码.它通过循环或Streams API在迭代应用程序方面提供的替代方案比在源代码中显式嵌套函数应用程序更清晰,更易于维护. (3认同)
  • @Alain O'Dea:我再次更改了数字,因为65534只是解决异常处理程序问题的建议.由于问题的方法不包含异常处理程序,理论上它可以使用65535个字节.请注意,对于普通的Java代码,异常处理程序问题无论如何都不相关,因为异常处理程序不会覆盖它们自己,换句话说,您可以通过重新排序代码来解决问题,以便一个异常处理程序不被另一个异常处理程序覆盖.最后,因此消除了异常处理程序覆盖65535th指令的需要. (2认同)
  • @Brian Goetz:在这种特殊情况下,运行时堆栈并不重要,因为每次调用都会在下一次调用完成之前完成.这不是递归.好吧,除非我们谈论编译器的堆栈...... (2认同)