英文:
How to ignore StackOverFlow error in Java?
问题
我知道为什么会出现错误,我不想去修正它,我希望系统忽略它继续运行。
我知道递归不是无限的,我需要知道它何时会停止,尽管我确信会是一个很大的数字,并且经过相当长的时间执行后会停止。
谢谢。
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
英文:
I know why it gives the error, I don't want to correct it I want the system to ignore it and keep running.
I know that the recursion is not infinite and I need to know when it will stop although I am sure it will be in a very large number and after a good while of execution.
Thankssss.
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
答案1
得分: 3
>我知道递归不是无限的
你“知道”一个错误。
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
考虑一下如果我们调用 fun1(0, 1, 0)
会发生什么。
begin >= end
吗?不,begin == 0
而且 end == 1
。所以我们进行递归。
我们递归调用的参数是什么?(begin + end) / 2
等于 (0 + 1) / 2
等于 1 / 2
,使用整数除法得到 0。所以第一个递归调用是 fun1(0, 0, 0)
。
但是最后一个递归调用是 fun1(0, 1, 0)
。等等。那看起来很熟悉,对吧?(不要介意中间那个;我们已经展示了一个错误。)
英文:
>I know that the recursion is not infinite
You "know" a falsehood.
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
Consider what happens if we call fun1(0, 1, 0)
.
Is begin >= end
? No; begin == 0
and end == 1
. So we recurse.
What are the arguments for our recursive calls? (begin + end) / 2
is equal to (0 + 1) / 2
is equal to 1 / 2
is equal to 0, with integer division. So the first recursive call is fun1(0, 0, 0)
.
But the last recursive call is fun1(0, 1, 0)
. Wait. That looks familiar, yeah? (Never mind the middle one; we have already shown a fault.)
答案2
得分: 1
@Karl's answer解释了为什么你的函数实际上是无限递归的。
但是你问道:
> 如何忽略Java中的StackOverflow错误?
你不能简单地忽略它。如果这样做,程序会崩溃(或者一个子线程会终止,或者其他情况),你将得不到答案。
你可以这样做:
Integer result = null;
try {
result = fun1(x, y, z);
} catch (StackOverflowError e) {
// 我们在这里忽略了这个异常
}
if (result == null) {
System.out.println("无法计算 fun1(x, y, z)");
} else {
System.out.println("fun1(x, y, z) 为 " + result);
}
但是当你看这段代码时,实际上我们并没有真正地忽略异常。我们捕获了它,然后(最终)将其作为一种特殊情况进行处理。
请注意,即使在递归不是无限的情况下,你也可能会遇到 StackOverflowError
。例如,如果我使用递归来相加两个数:
public int add(int a, int b) {
if (a < 0 || b < 0) {
throw new IllegalArgumentException("负数");
} else if (a == 0) {
return b;
} else {
return add(a - 1, b + 1);
}
}
由于Java(通常情况下)不执行尾递归优化,足够大的参数会导致 StackOverflowError
。
那么在函数不是无限递归的情况下,如何解决 StackOverflowError
呢?
-
一种方法是使用更大的线程堆栈大小。可以通过使用
-Xss<value>
选项来设置JVM的默认堆栈大小。或者,在创建新线程时可以通过Thread
构造函数提供堆栈大小。然而,实际可行的线程堆栈大小受可用内存量的限制,还有可能受到JVM、操作系统和硬件架构的限制。 -
第二种方法是将递归函数转换为迭代形式。但要注意,如果只是使用软件中实现的堆栈来模拟递归调用,就必须处理数据结构可能变得过大的情况。
-
第三种方法是尝试找到代数解;即将问题转化为数学问题。
但要注意,有些情况下上述方法都不起作用。例如,考虑一下阿克曼函数。
英文:
@Karl's answer explains why your function is actually infinitely recursive.
But you asked:
> How to ignore StackOverFlow error in Java?
You cannot simply ignore it. If you do that, the program crashes (or a child thread dies, or something) and you don't get an answer.
You could do this:
Integer result = null;
try {
result = fun1(x, y, z);
} catch (StackOverflowError e) {
// We are ignoring this
}
if (result == null) {
System.out.println("cannot compute fun1(x,y,z)");
} else {
System.out.println("fun1(x,y,z) is " + result);
}
But when you look at this, we are not really ignoring the exception. We are catching it and (ultimately) dealing with it as a special case.
Note that you can get a StackOverflowError
even in cases where the recursion is not infinite. For example, if I was to add two numbers using recursion:
public int add(int a, int b):
if (a < 0 || b < 0) {
throw new IllegalArgumentException("negative");
else if (a == 0) {
return b;
} else
return add(a - 1, b + 1);
}
Since Java (typically) doesn't do tail-call optimization, large enough arguments will give a StackOverflowError
.
So what it the solution to StackOverflowError
s in cases where the function is not infinitely recursive?
-
One approach would be to use a larger thread stack size. This could be done by using the
-Xss<value>
option to set the default stacksize for the JVM. Alternatively, you can supply a stack size via theThread
constructor when creating a new thread. However, the maximum practical thread stack size is limited by the amount of available memory, and potentially by JVM, OS and hardware architectural limits. -
A second approach is to translate the recursive function into an iterative form. But note that if you simply simulate the recursive calls using a stack implemented in software, you have to deal with the possibility that that data structure gets too big.
-
A third approach is to try and find an algebraic solution; i.e. turn this into a mathematical problem.
But note that there are some cases where none of the above will work. For example, consider the Ackermann function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论