替代System.exit(1)的方法

26

由于各种原因,在编写Java应用程序时,调用System.exit被认为是不好的,那么我该如何通知调用进程事情未按计划进行?

编辑:1是任何非零退出代码的替身

9个回答

33

System.exit在作为较大Java应用程序(服务器)的子应用程序(例如servlet,applet)时使用不被赞同:在这种情况下,System.exit可能会停止JVM,从而也停止所有其他子应用程序。在这种情况下,抛出适当的异常,并通过应用程序框架/服务器捕获和处理它是最好的选择。

如果Java应用程序真的是要作为独立应用程序运行,那么使用System.exit没有问题。在这种情况下,设置退出值可能是向父进程通信失败或成功的最简单(也是最常用)方法。


当使用 System.exit() 时,如何确保开放资源被关闭? - Roland
这正是我所思考的。System.exit() 应该只用于最简单的应用程序,这些应用程序具有单个进程,因此您知道在 main() 的最后什么都没有打开(除非您忘记关闭某些内容)。 - Franz D.

10

我赞同“抛出异常”的做法。其中一个原因是,调用 System.exit 会使你的代码难以使用,如果你希望其他代码能够使用它。例如,如果你发现你的类对 Web 应用程序或某种消息消费应用程序有用,那么允许这些容器以某种方式处理失败将是很好的。容器可能希望重试操作、决定记录并忽略问题、向管理员发送电子邮件等。

一个例外是你的 main() 方法;它可以捕获异常,并使用一些值调用 System.exit(),这些值可以被调用进程或 shell 脚本识别。


如果您的应用程序启动了另一个线程,然后该线程被 System.exit() 强制终止,这可能会导致数据损坏,仍然存在问题。 - Franz D.

3

System.exit()会导致阻塞,并且如果启动它的线程在shutdown hook中使用,就会创建死锁。


2
我们公司的政策是,可以(甚至更好)在init()方法中调用System.exit(-1),但在程序正常流程中调用时一定要三思而后行。

你们公司真的很不错 XD - Franz D.

2

我认为当出现问题时,抛出异常是您应该采取的措施。这样,如果您的应用程序不是作为独立应用程序运行,调用者就可以对其做出反应,并获得有关出现何种问题的某些信息。这也更容易进行调试,因为当您看到堆栈跟踪时,您可以更好地了解出现了什么问题。

值得注意的一点是,当异常达到顶层并因此导致VM退出时,VM会返回一个返回代码1,因此使用返回代码的外部应用程序会看到发生了错误。

唯一我认为System.exit()有意义的情况是,当您的应用程序旨在由非Java应用程序调用时,这些应用程序必须使用返回代码来查看您的应用程序是否工作正常,并且您希望这些应用程序有机会因不同的问题而作出不同的反应,即您需要不同的返回代码。


1

在Web Servlet环境中,这也可能是危险/有问题的。

抛出异常通常被认为是另一种选择。


1

抛出异常是将有关特定错误的信息发送到应用程序之外的最佳方式。

一个数字告诉你的不如:

Exception at thread 'main': FileNotFoundException "The file 'foo' doesn't exist"

(或者类似这样的)


是的,但如果你想在脚本(或批处理)中使用该应用程序,你需要向系统提供一些错误代码。 - Franz D.

0

我也想要加入一些我的看法。当我编写应用程序时,这个问题总是会出现。

正如大家都同意的那样,使用System.exit()需要小心,如果可能的话,应该使用异常。然而,System.exit()似乎仍然是向系统返回基本信息的唯一方法,因此如果您想使您的应用程序可脚本化,则需要使用它。如果您不需要这个功能,只需抛出异常即可。

但是,如果(仅当)您的应用程序是单线程的,则可以使用它——可以保证没有其他东西正在进行,并且没有资源处于打开状态(至少如果您始终使用try-with-resource习惯用法,我强烈建议这样做,因为它还可以使代码更清晰、更紧凑)。

另一方面,一旦您的应用程序创建任何可能写入资源的线程,System.exit()就是完全“不行”的,因为它可能(并且随着时间的推移,将)破坏数据。

为了能够使用多线程和脚本应用程序并仍然保证数据完整性,我目前的最佳解决方案是保存您创建的任何修改资源的线程(例如通过始终使用将线程添加到列表中的工厂方法),并安装一个关闭挂钩来清除地结束每个线程,即通过中断和加入它。由于关闭挂钩也被System.exit()调用,这将保证(减去编程错误)不会在资源写入中间杀死任何线程。
哦,是的,也许我甚至不应该提到它,但是:永远不要使用那个可怕的System.halt()方法。它只是直接终止虚拟机而不调用任何关闭挂钩。

0

在正常情况下,使用System.exit是不受欢迎的。如果“不是一切都按计划进行”,那么可以使用System.exit。

更新:我应该补充说明的是,我假设您的“1”在某个地方有记录的含义。


这仅适用于最简单的单线程命令行工具。一旦创建任何修改某些资源(写入文件)的线程,就可能会破坏您的数据。 - Franz D.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接