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

Java 当我想抛出异常时,退出程序的最佳方法是什么?,java,exception-handling,Java,Exception Handling,我正在写一个Java程序,它读取一个单词文件。程序主要依赖于这个文件,所以我真的希望程序在读取文件时,如果出于任何原因出现IOException,那么程序结束 结束节目的最佳方式是什么?我想我被迫将文件读取包围在try/catch块中,所以我应该在catch中添加System.exit(0)?例如,我是否应该执行以下操作 try { BufferedReader br = new BufferedReader(new FileReader("myfile.txt")); String l

我正在写一个Java程序,它读取一个单词文件。程序主要依赖于这个文件,所以我真的希望程序在读取文件时,如果出于任何原因出现IOException,那么程序结束

结束节目的最佳方式是什么?我想我被迫将文件读取包围在try/catch块中,所以我应该在catch中添加
System.exit(0)
?例如,我是否应该执行以下操作

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); // ???
}

如果让异常一直传播到
main()
方法,程序将结束。无需调用
System.exit
,只需允许异常在堆栈中自然冒泡(通过向必要的方法添加
抛出IOException


编辑:正如@Brian所指出的,您可能希望捕获
main
方法中的
IOException
,并调用
系统。退出那里,提供一条人类可读的错误消息(堆栈跟踪可能会吓到人)。另外,正如@MeBigFatGuy所说,从代码堆栈内部调用
System.exit
是一种不好的做法,并且限制了代码的可重用性。如果必须使用
System.exit
,请将其保存在
main
方法的主体中。

没关系。但是
0
作为退出代码意味着程序按预期结束。您需要使用不同的号码;)

如果您真的希望立即终止该程序,而不是让程序的高层决定该做什么(也许有一天您的程序核心将被扩展,允许从各种网站为
myfile.txt
选择源代码,或语音到文本合成,或直接脑转移),您应该调用:
System.exit(1)
(或其他非零退出状态)

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

./fiddle_with_words myfile.txt || mail -s "program failed" grautur@example.com

@格拉特在评论@skaffman的回答时问道


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

我想这要视情况而定。如果异常只需要冒出少量级别,并且方法传播
IOException
是有意义的,那么这就是您应该做的。允许异常传播并没有什么特别“讨厌”的地方

另一方面,如果
IOException
必须在多个级别上传播,并且不可能在某个特定点之外对其进行专门处理,则您可能需要:

  • 定义一个自定义的
    ApplicationErrorException
    ,它是
    RuntimeException
    的子类
  • 捕获源附近的
    IOException
    ,并在其位置抛出一个
    ApplicationErrorException
    。。。用
    原因
    设置当然,和
  • main
    方法中捕获
    ApplicationErrorException
    异常
main
中捕获
ApplicationErrorException
的点上,可以使用非零状态代码调用
System.exit()
,并可以选择打印或记录堆栈跟踪。(事实上,您可能希望通过专门化“应用程序错误”异常来区分是否需要堆栈跟踪。)

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



使这个问题复杂化的最后一件事是在除
main
线程之外的某些线程堆栈上抛出的异常。您可能不希望处理异常并将其转换为另一个线程堆栈上的
System.exit()
。。。因为这不会给其他线程一个完全关闭的机会。另一方面,如果不执行任何操作,则默认行为是另一个线程仅以未捕获的异常终止。如果线程中没有任何内容
join()。不幸的是,没有简单的“一刀切”解决方案。

这还有一个额外的好处,即如果其他程序想重用您的代码,您不会杀死该程序。该程序可以自行决定如何处理异常。实际上,调用
系统是有很好的理由的。退出
;返回有意义的退出代码和比堆栈跟踪更好的错误消息。不这样做的唯一原因是,如果您希望使用用户友好的消息而不是丑陋的堆栈跟踪退出。不过,堆栈跟踪可能会提供更好的诊断信息。您仍然可以让它冒泡到main,在那里提供通用的try/catch,并优雅地结束程序。因此,如果我理解正确,我可以通过删除try/catch块并向该方法添加“throws IOException”来让异常冒泡(还有调用该方法的方法,等等)?我觉得这样做有点恶心,因为现在我必须添加一堆“抛出IOException”s无处不在——我的恶心是不是被误导了?遗憾的是,即使在2013年,直接脑转移仍然不是现实。*悲哀*@Thomas没有气垫车!为什么还要为没有气垫车和直接脑转移的未来而烦恼呢。。。