[英]Java Riddle with finally block and recursion
我刚刚为我们的团队准备了一个关于 java 谜语的游戏。 可以这么说,一小段 java 代码会做一些乍看之下意想不到的事情。
在搜索这些谜语的同时,我还在我的 IDE 中乱涂乱画,并尝试了一些你永远不会在生产代码中编写的奇怪东西。 就是图个好玩儿。
我突然想到了以下几点:
public static int cnt = 0;
public static int blubb() {
try {
cnt++;
return blubb();
} finally {
return cnt;
}
}
public static void main(String[] args) {
System.out.println(cnt + ": " + Main.blubb() + ": " + cnt);
}
执行时,它会打印类似“0:21245:21245”的内容,其中每次运行的 21245 都不同。
我希望要么无限递归,要么在 finally 块中返回 1 (0: 1: 1)
当添加一个 catch 块来捕获 Throwable 和调试时,调试器将永远不会停止在这个块中。
有人可以解释一下这里发生了什么吗?
像这样添加一个catch
块,但没有看到堆栈跟踪,并不表示没有抛出任何东西:
} catch (Throwable t) {
t.printStackTrace();
throw t;
} finally { ... }
预计在捕获StackOverflowError
后无法立即打印StackOverflowError
的堆栈跟踪:SOE 字面意思是不能进行更多的方法调用。
但是要调用printStackTrace()
,您需要进行另一个方法调用。 因此,该方法调用实际上会导致另一个单独的StackOverflowError
,您不会尝试打印它。 但随后 finally 中的return
导致StackOverflowError
被丢弃。
试试这个,当StackOverflowError
被抛出时不需要方法调用:
import java.util.*;
class Main {
public static int cnt = 0;
private static Throwable caught;
public static int blubb() throws Throwable {
try {
cnt++;
return blubb();
} catch (Throwable t) {
caught = t;
throw t;
} finally {
return cnt;
}
}
public static void main(String[] args) throws Throwable {
System.out.println(cnt + ": " + Main.blubb() + ": " + cnt);
System.out.println(caught);
}
}
对我来说,这打印:
0: 9672: 9672
java.lang.StackOverflowError
所以是的,一个StackOverflowError
被捕获了。
您创建了一个无限递归循环。
有时调用堆栈变得如此之大,它会引发StackOverflowError
并且您的应用程序应该崩溃。
但是您在try
块中设置了递归调用。 所以异常被部分处理,而不是因为你没有catch
块而被显示。
由于您有一个finally
块返回cnt
的值,因此堆栈中的许多调用都会返回该值,然后返回19543
或在异常之前调用它的任何次数。
TL;DR:使用try
块时,不要隐藏异常
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.