Java中的 StackOverflowError 示例
StackOverflowError是Java不允许捕获的错误,例如,堆栈空间不足,因为它是人们可能遇到的最常见的运行时错误之一。
StackOverflowError 的主要原因是我们没有为递归函数或模板提供正确的终止条件,这意味着它将变成一个无限循环。
StackOverflowError 什么时候遇到?
当我们调用一个方法时,会在调用堆栈或线程堆栈大小上创建一个新的堆栈帧。这个堆栈帧保存被调用方法的参数,主要是局部变量和方法的返回地址。这些堆栈帧的创建将是迭代的,并且仅当在嵌套方法中找到方法调用的结尾时才会停止。在此过程中,如果 JVM 用完需要创建的新堆栈帧的空间,它将抛出 StackOverflowError。
例如:缺乏适当的终止条件或没有终止条件。这主要是导致这种情况的原因,称为未终止或无限递归。
下面给出的是无限递归的实现:
// Java program to demonstrate
// infinite recursion error
public class StackOverflowErrorClass {
static int i = 0;
// Method to print numbers
public static int printNumber(int x)
{
i = i + 2;
System.out.println(i);
return i + printNumber(i + 2);
}
public static void main(String[] args)
{
// Recursive call without any
// terminating condition
StackOverflowErrorClass.printNumber(i);
}
}
运行时错误:
RunTime Error in java code :- Exception in thread “main” java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:597)
at java.io.PrintStream.println(PrintStream.java:736)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:13)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:14)
at StackOverflowErrorClass.printNumber(StackOverflowErrorClass.java:14)
.
.
.
注意:请在您的系统上运行此程序以查看抛出的错误,由于堆栈大小,在线 IDE 上可能不会显示错误。
如何修复 StackOverflowError?
- 避免重复调用:尝试为递归调用引入适当的终止条件或某些条件,以确保它终止。
下面给出了具有适当终止条件的实现:
// Java Program to demonstrate proper // use of terminating condition // Printing natural numbers public class stackOverflow { static int i = 0; public static int printNumber(int x) { i = i + 2; System.out.println(i); // Terminating condition if (i == 10) return i; return i + printNumber(i + 2); } public static void main(String[] args) { stackOverflow.printNumber(i); } }
输出:2 4 6 8 10
- 增加堆栈大小:第二种方法可能是,如果您注意到它已正确实现,但我们仍然看到错误,那么我们只能通过增加堆栈大小来避免这种情况,以便存储所需数量的递归调用。这是通过更改编译器的设置来实现的。
类之间的循环关系是两个不同的类在它们的构造函数中相互实例化时产生的关系。
遇到 StackOverflowError 是因为 Class A1 的构造函数正在实例化 Class A2,而 Class A2 的构造函数又实例化 Class A1,反复出现,直到我们看到 StackOverflow。这个错误主要是由于构造函数调用不好,即相互调用,这甚至不是必需的,也没有任何意义,所以我们可以避免在代码中引入它们。
下面给出的是类之间循环关系的实现:
// Java Program to demonstrate // cyclic relationship between class public class A1 { public A2 type2; public A1() { // Constructor of A2 is called // hence object of A2 is created type2 = new A2(); } public static void main(String[] args) { // Cycle is started by // invoking constructor of class A1 A1 type1 = new A1(); } } class A2 { public A1 type1; public A2() { // Constructor of A1 is called // hence object of A1 is created type1 = new A1(); } }
运行时错误:
RunTime Error in java code :- Exception in thread “main” java.lang.StackOverflowError
at A2.(A1.java:32)
at A1.(A1.java:13)
at A2.(A1.java:32)
.
.
.注意:这将不断重复,这些无限循环调用可以看到无限递归。