由于各种原因,在编写Java应用程序时,调用System.exit
被认为是不好的,那么我该如何通知调用进程事情未按计划进行?
编辑:1是任何非零退出代码的替身
。
System.exit
在作为较大Java应用程序(服务器)的子应用程序(例如servlet,applet)时使用不被赞同:在这种情况下,System.exit
可能会停止JVM,从而也停止所有其他子应用程序。在这种情况下,抛出适当的异常,并通过应用程序框架/服务器捕获和处理它是最好的选择。
如果Java应用程序真的是要作为独立应用程序运行,那么使用System.exit
没有问题。在这种情况下,设置退出值可能是向父进程通信失败或成功的最简单(也是最常用)方法。
我赞同“抛出异常”的做法。其中一个原因是,调用 System.exit 会使你的代码难以使用,如果你希望其他代码能够使用它。例如,如果你发现你的类对 Web 应用程序或某种消息消费应用程序有用,那么允许这些容器以某种方式处理失败将是很好的。容器可能希望重试操作、决定记录并忽略问题、向管理员发送电子邮件等。
一个例外是你的 main()
方法;它可以捕获异常,并使用一些值调用 System.exit()
,这些值可以被调用进程或 shell 脚本识别。
System.exit()
会导致阻塞,并且如果启动它的线程在shutdown hook中使用,就会创建死锁。
我认为当出现问题时,抛出异常是您应该采取的措施。这样,如果您的应用程序不是作为独立应用程序运行,调用者就可以对其做出反应,并获得有关出现何种问题的某些信息。这也更容易进行调试,因为当您看到堆栈跟踪时,您可以更好地了解出现了什么问题。
值得注意的一点是,当异常达到顶层并因此导致VM退出时,VM会返回一个返回代码1,因此使用返回代码的外部应用程序会看到发生了错误。
唯一我认为System.exit()有意义的情况是,当您的应用程序旨在由非Java应用程序调用时,这些应用程序必须使用返回代码来查看您的应用程序是否工作正常,并且您希望这些应用程序有机会因不同的问题而作出不同的反应,即您需要不同的返回代码。
在Web Servlet环境中,这也可能是危险/有问题的。
抛出异常通常被认为是另一种选择。
抛出异常是将有关特定错误的信息发送到应用程序之外的最佳方式。
一个数字告诉你的不如:
Exception at thread 'main': FileNotFoundException "The file 'foo' doesn't exist"
(或者类似这样的)
我也想要加入一些我的看法。当我编写应用程序时,这个问题总是会出现。
正如大家都同意的那样,使用System.exit()
需要小心,如果可能的话,应该使用异常。然而,System.exit()
似乎仍然是向系统返回基本信息的唯一方法,因此如果您想使您的应用程序可脚本化,则需要使用它。如果您不需要这个功能,只需抛出异常即可。
但是,如果(仅当)您的应用程序是单线程的,则可以使用它——可以保证没有其他东西正在进行,并且没有资源处于打开状态(至少如果您始终使用try-with-resource习惯用法,我强烈建议这样做,因为它还可以使代码更清晰、更紧凑)。
另一方面,一旦您的应用程序创建任何可能写入资源的线程,System.exit()就是完全“不行”的,因为它可能(并且随着时间的推移,将)破坏数据。
为了能够使用多线程和脚本应用程序并仍然保证数据完整性,我目前的最佳解决方案是保存您创建的任何修改资源的线程(例如通过始终使用将线程添加到列表中的工厂方法),并安装一个关闭挂钩来清除地结束每个线程,即通过中断和加入它。由于关闭挂钩也被System.exit()
调用,这将保证(减去编程错误)不会在资源写入中间杀死任何线程。System.halt()
方法。它只是直接终止虚拟机而不调用任何关闭挂钩。在正常情况下,使用System.exit是不受欢迎的。如果“不是一切都按计划进行”,那么可以使用System.exit。
更新:我应该补充说明的是,我假设您的“1”在某个地方有记录的含义。
System.exit()
时,如何确保开放资源被关闭? - Roland