当我想要抛出异常时退出程序的最佳方法是什么?

gra*_*tur 24 java exception-handling

我正在编写一个读取文件的Java程序.该方案在很大程度上取决于这个文件,所以我真的希望程序结束时,如果出于某种原因没有读取文件时是一个IOException.

结束该计划的最佳方式是什么?我想我被迫在try/catch块中包围我的文件读取,所以我应该System.exit(0)在catch中添加一个内容吗?例如,我应该做以下的事情吗?

try {
  BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
  String line;
  while ((line = br.readLine()) != null) {
    // process...
  }
} catch(IOException e) {
  System.out.println("Error: " + e);
  System.exit(0); // ???
}
Run Code Online (Sandbox Code Playgroud)

ska*_*man 35

如果让异常一直传播到main()方法,程序将结束.没有必要调用System.exit,只是允许异常自然地(通过添加throws IOException)向必要的方法冒泡堆栈.

编辑:正如@Brian指出的那样,你可能想要捕获IOException你的main方法,System.exit而是在那里调用,提供一个人类可读的错误消息(堆栈跟踪可以吓唬人).另外,正如@MeBigFatGuy所说,System.exit从代码堆栈内部调用是不好的做法,并限制了代码的可重用性.如果必须使用System.exit,请将其保留在main方法体内.

  • 这有一个额外的好处,如果一些其他程序想要重用您的代码,您将不会杀死该程序.该程序可以自行决定如何处理异常. (2认同)
  • 实际上,调用“System.Exit”是有充分理由的;返回有意义的退出代码和比堆栈跟踪更好的错误消息。 (2认同)
  • 因此,如果我理解正确,我通过删除try/catch块并向该方法添加"throws IOException"(以及调用该方法的方法等)来让异常冒泡?我觉得有点蠢,因为现在我必须添加一堆"抛出IOException"到处 - 我的ickiness被误导了? (2认同)

Bri*_*ach 10

没关系.但是0,退出代码表示程序按预期结束.你会想要使用不同的数字;)


sar*_*old 8

如果你真的希望立即终止程序,而不是让程序的上层决定做什么(可能你的程序的核心将在某一天延长,以允许myfile.txt从各种网站选择一个来源,或者语音到 -文本合成,或直接脑转移),你应该调用:( System.exit(1)或其他一些非零退出状态).

0对shell执行的退出代码(以及父进程)执行正常完成.非零退出代码报告存在错误.这对于制作出色的工具来通知管理员异常执行错误或编写友好的小程序至关重要:

./fiddle_with_words myfile.txt || mail -s "program failed" grautur@example.com
Run Code Online (Sandbox Code Playgroud)


Ste*_*n C 5

@gratur 在对@skaffman 的回答发表评论时提问。

因此,如果我理解正确,我会通过删除 try/catch 块并向该方法(以及调用该方法的方法等)添加“throws IOException”来让异常冒泡?我觉得这样做有点恶心,因为现在我必须在任何地方添加一堆“抛出 IOException”——我的恶心是否被误导了?

我认为这取决于。如果异常只需要冒出少量级别,并且方法传播 an 是有意义的IOException,那么这就是您应该做的。允许异常传播并没有什么特别“讨厌”的地方。

另一方面,如果IOException必须通过多个级别传播并且不可能在某个点之外专门处理它,您可能需要:

  • 定义一个自定义ApplicationErrorException,它是 的子类RuntimeException
  • 抓住IOException靠近它的源头并ApplicationErrorException在它的位置扔一个......cause当然,和
  • ApplicationErrorException在您的main方法中捕获异常。

main捕获 时ApplicationErrorException,您可以System.exit()使用非零状态代码进行调用,并可选择打印或记录堆栈跟踪。(实际上,您可能希望通过专门化您的“应用程序错误”异常来区分您需要和不需要堆栈跟踪的情况。)

请注意,main出于@skaffman 的回答中解释的原因,我们仍然允许将异常传播到...。


使这个问题复杂化的最后一件事是在线程以外的某个线程的堆栈上抛出的异常main。您可能不希望异常被处理并变成System.exit() 另一个线程堆栈上的...... 因为这不会给其他线程一个干净地关闭的机会。另一方面,如果你什么都不做,默认行为是另一个线程以未捕获的异常终止。如果join()线程中没有任何内容,则可能会被忽视。不幸的是,没有简单的“一刀切”的解决方案。