Scala StackOverflowError,而Java可以处理它

时间:2014-05-23 14:58:15

标签: java scala

我倾向于在S​​cala中编程并遇到这个问题,其中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。

2 个答案:

答案 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 : _*)