据我所知,这段代码应该抛出StackOverflowError,但事实并非如此.可能是什么原因?
public class SimpleFile { public static void main(String[] args) { System.out.println("main"); try{ SimpleFile.main(args); } catch(Exception e){ System.out.println("Catch"); } finally{ SimpleFile.main(args); } } }
Philip Couli.. 5
一个错误是不是Exception
.因此捕获任何异常都不会捕获StackOverflowError.
所以让我们从修复"明显的错误"开始 - (这个代码是不可取的,如本答案后面所述):
catch(Throwable e){ System.out.println("Catch"); }
如果进行此更改,您将发现代码仍然无法打印.但它没有打印出一个非常不同的原因......
抓住任何ERROR
(包括a StackOverflowError
)是非常沮丧的.但是在这里你不仅要抓住一个,而是抓住一个,因为它发生在堆栈顶部.即使使用您的代码(没有上述更改),该finally
块也可以有效地捕获错误.
StackOverflowError
当堆栈已满并且您尝试向其添加更多内容时,会发生A.因此,当您捕获错误时,堆栈仍然已满.您无法调用任何方法(甚至打印到控制台),因为堆栈已满.所以在它成功打印之前会StackOverflowError
抛出一秒钟catch
.
结果是:
捕获错误
尝试打印错误
导致另一个错误,因为它无法打印
调用finally
,因为最后总是被调用.
导致另一个错误,因为它无法调用 main
将错误级联回上一次调用,该调用遇到同样的错误.
这里的关键是最终会开始印刷.但是调用print
使用大量的堆栈空间和代码将需要通过上述点重复和错误很长一段时间才能释放足够的堆栈空间进行打印.根据Holger的评论,使用Oracle的Java 8将main
堆栈帧所需的println
堆栈帧数接近50.
250 = 1,125,899,906,842,624
这就是为什么你不应该抓住错误.
只有少数借口可以让你违反这条规则,并且你已经发现了如果你打破它可以解决的问题.
一个错误是不是Exception
.因此捕获任何异常都不会捕获StackOverflowError.
所以让我们从修复"明显的错误"开始 - (这个代码是不可取的,如本答案后面所述):
catch(Throwable e){ System.out.println("Catch"); }
如果进行此更改,您将发现代码仍然无法打印.但它没有打印出一个非常不同的原因......
抓住任何ERROR
(包括a StackOverflowError
)是非常沮丧的.但是在这里你不仅要抓住一个,而是抓住一个,因为它发生在堆栈顶部.即使使用您的代码(没有上述更改),该finally
块也可以有效地捕获错误.
StackOverflowError
当堆栈已满并且您尝试向其添加更多内容时,会发生A.因此,当您捕获错误时,堆栈仍然已满.您无法调用任何方法(甚至打印到控制台),因为堆栈已满.所以在它成功打印之前会StackOverflowError
抛出一秒钟catch
.
结果是:
捕获错误
尝试打印错误
导致另一个错误,因为它无法打印
调用finally
,因为最后总是被调用.
导致另一个错误,因为它无法调用 main
将错误级联回上一次调用,该调用遇到同样的错误.
这里的关键是最终会开始印刷.但是调用print
使用大量的堆栈空间和代码将需要通过上述点重复和错误很长一段时间才能释放足够的堆栈空间进行打印.根据Holger的评论,使用Oracle的Java 8将main
堆栈帧所需的println
堆栈帧数接近50.
250 = 1,125,899,906,842,624
这就是为什么你不应该抓住错误.
只有少数借口可以让你违反这条规则,并且你已经发现了如果你打破它可以解决的问题.