Java中如何在堆栈溢出时使用try/catch?

29

你能在Java中使用try/catch捕获堆栈溢出异常吗?无论如何,似乎它都会抛出自己。当我的程序溢出时,我想要“惩罚”该值。


14
预防胜于治疗。 - Mitch Wheat
7
调试时捕获异常很有用 :) - JonnyBoy
1
不犯错误比调试更好笑,开个玩笑。 - Andrew
想象一下,你有一个测试文件,其中存储了1000个测试用例。在防止错误之前,您可能想知道哪个测试用例首先出现了错误... - yılmaz
5个回答

36

似乎可以正常工作:

public class Test {

    public static void main(String[] argv){
        try{
            main(null);
        }
        catch(StackOverflowError e){
            System.err.println("ouch!");
        }
    }

}

3
啊,我一直在尝试使用通用异常。谢谢! - stereos
我同意找出导致异常的原因并防止它会更好。 - Thilo
12
你并不是试图捕获“Exception”异常,而是在寻找“Error”。Error直接继承自Throwable,而不是通过Exception继承。 - Tom Hawtin - tackline

8

如果你遇到栈溢出的情况,很可能是在尝试无限递归或过度滥用函数调用。也许你可以考虑将一些过程迭代化,而不是递归,或者仔细检查你的递归过程中是否有正确的基本情况。捕获栈溢出异常是一个坏主意;这只是治标不治本。


在使用递归和 JVM 的设置选项溢出的情况下,SO 是一个正确程序的普通负面答案。我们必须捕获并做出反应。例如,在懒惰序列的情况下,由递归函数设置(https://dev59.com/XZHea4cB1Zd3GeqPnErB#33926444),我们可以通过更小的步骤简单地继续前进。 - Gangnus
1
捕获SO错误在调试时也非常有用,特别是当您不知道哪个递归方法导致SO错误时 :) - Ahmed Nassar
如果堆栈溢出是由你的代码引起的,我同意。我目前正在与一个由用户数据引起的堆栈溢出进行斗争,这些数据是由我使用的库处理的。所以我无法做任何事情来避免它。 - Stefan Steinegger

5
你需要捕获错误,而不是异常。

4

Java 8的功能特性使得这个问题变得异常重要。因为我们开始广泛使用递归,StackOverflowException是我们必须考虑的事情。

Java 8的lambda类型中没有一个抛出StackOverflowException。因此,我们必须自己创建。这是绝对必要的,否则甚至无法通过IDE控制。

例如,Integer -> Integer函数类型可以如下:

@FunctionalInterface
public interface SoFunction <U> {
    public U apply(Integer index) throws StackOverflowException;
}

接下来,我们可以编写一个函数,该函数将接受抛出StackOverflowException的lambda表达式。

public T get(int currentIndex) throws StackOverflowException{

现在我们可以创建一个递归lambda函数:

fiboSequence.setSequenceFunction(
            (i) ->
            fiboSequence.get(i-2).add(fiboSequence.get(i-1))
);

接下来,我们可以调用递归链fiboSequence.get(i)并得到结果或者如果整个链无法计算则会出现StackOverflowException。

在使用递归时,SO的意义完全不同:您已经跳得太深了,请将其分解成更浅的步骤再重复操作。


0
有时候由于代码的性质,需要增加(依赖于操作系统)堆栈大小,通常在Linux上每个线程为1m。
如果您确定代码已经针对您的用例进行了优化,但仍然遇到此错误,则可以使用-Xss2m来增加VM的堆栈大小。请参阅Oracle文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接