我倾向于在Scala中编程并遇到这个问题,其中Scala代码抛出StackOverflowErorr,而Java中的类似实现可以在抛出相同的错误之前多一点
def recursiveSum(args: Int*): Int = {
if (args.length == 0) 0
else
args.head + recursiveSum(args.tail: _*)
}
recursiveSum(5000 to 15000: _*)
我得到的错误是
java.lang.StackOverflowError
//| at scala.collection.Parallelizable$class.$init$(Parallelizable.scala:20)
//| at scala.collection.AbstractTraversable.<init>(Traversable.scala:105)
//| at scala.collection.AbstractIterable.<init>(Iterable.scala:54)
//| at scala.collection.AbstractSeq.<init>(Seq.scala:40)
//| at scala.collection.immutable.Range.<init>(Range.scala:44)
//| at scala.collection.immutable.Range$Inclusive.<init>(Range.scala:330)
//| at scala.collection.immutable.Range$Inclusive.copy(Range.scala:333)
//| at scala.collection.immutable.Range.drop(Range.scala:170)
//| at scala.collection.immutable.Range.tail(Range.scala:196)
//| at scala.collection.immutable.Range.tail(Range.scala:44)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$main$1.recursiveSum$1(Loops.scala:11)
//| at Loops$$anonfun$m
//| Output exceeds cutoff limit.
java代码是
static int recursiveSum(int... arg) {
if (arg.length == 0)
return 0;
else
return arg[0] + recursiveSum(Arrays.copyOfRange(arg, 1, arg.length));
}
public static void main(String[] args) {
System.out.println(recursiveSum(range(5000, 15000)));
}
private static int[] range(int i, int j) {
int list[] = new int[j - i + 1];
int idx = 0;
for (int s = i; s <= j; s++)
list[idx++] = s;
return list;
}
为什么Scala的尾递归优化没有帮助? Java如何处理(Java无法处理超过15000个16000)?
它们在同一个eclipse ide上运行,桌面计算机上的默认堆栈大小为java 7。
答案 0 :(得分:7)
这不是尾递归。为了使函数成为尾递归,函数中的最后一个语句(尾部)需要是递归调用。在您的情况下,它可能看起来像,但如果您使用@tailrec
注释注释您的函数,您将看到它不是。实际上,你的最后一个语句是一个补充,而不是递归调用。
如果您重写函数以使用累加器,那么您将能够执行尾递归版本...
def recursiveSum(args: Int*): Int = {
@tailrec
def sumAccumulator(sum: Int, args: Int*): Int = {
if(args.length == 0) sum
else sumAccumulator(sum + args.head, args.tail: _*)
}
sumAccumulator(0, args: _*)
}
recursiveSum(5000 to 15000: _*)
答案 1 :(得分:2)
对于尾递归,您的函数格式不正确。您可以通过(尝试)添加@tailrec注释来验证这一点。
scala> import annotation.tailrec
import annotation.tailrec
scala> @tailrec def recursiveSum(args: Int*): Int = {
| if (args.length == 0) 0
| else
| args.head + recursiveSum(args.tail: _*)
|
| }
<console>:11: error: could not optimize @tailrec annotated method recursiveSum: it contains a recursive call not in tail position
args.head + recursiveSum(args.tail: _*)
^
这是一个有效的解决方案:
import annotation.tailrec
def recursiveSum(args: Int*): Int = {
@tailrec def recursiveSumInternal(sum : Int, args: Int*): Int = {
if (args.length == 0)
sum
else
recursiveSumInternal(sum+args.head, args.tail: _*)
}
recursiveSumInternal(0, args: _*)
}
recursiveSum(5000 to 15000 : _*)