System.exit 的替代方案,可以将错误代码发送到批处理或 shell
Posted
技术标签:
【中文标题】System.exit 的替代方案,可以将错误代码发送到批处理或 shell【英文标题】:Alternates for System.exit that could send error codes to batch or shell 【发布时间】:2015-08-17 06:34:03 【问题描述】:我的 java 应用程序中有一组错误代码。目前我正在使用System.exit(code);
将错误代码从应用程序返回到外部应用程序。
System.exit
是否有任何替代品,因为使用它是不好的做法,因为它可能会关闭整个 JVM。
【问题讨论】:
你的问题没有意义。将代码返回给外部应用程序的唯一方法是作为进程退出代码。 它会关闭JVM,但是如果你想要退出,为什么会有问题呢?System.exit()
是退出应用程序的“坏”方式。许多静态分析工具都强调它。原因是您在退出之前可能没有清理所有内容。对于用户来说,这也可能是相当令人困惑的。在我看来,你“应该”使用它的唯一原因(在正常情况下)是如果你想向 shell 返回一个退出代码。
我刚刚想到了它不好的另一个原因:可重用性。如果你的代码中充满了System.exit()
,它可能会给想要在更大的应用程序中使用你的代码的人带来问题。就像goto
一样,它可以用作结束您的应用程序的捷径,而无需干净地展开您的堆栈。最后,如果有人想使用你的代码,他们不仅需要删除你所有的System.exit()
,而且他们可能还需要重构你的代码!
【参考方案1】:
我过去曾分享过你的经验,并试图设计出System.exit()
。一种可能性是留下 RuntimeException
未捕获,您将返回 1
到 shell,但最终如果您想要更多的多功能性(并且不希望丑陋的堆栈跟踪污染您的输出),您必须拥有至少“一次”呼叫System.exit()
。
public class Splat
public static void main(String[] args)
if (args.length > 0 && "splat".equals(args[0]))
throw new RuntimeException("splat");
输出:
$ java Splat
$ echo $?
> 0
$ java Splat splat
> Exception in thread "main" java.lang.RuntimeException: splat
> at Splat.main(Splat.java:9)
$ echo $?
> 1
我这样做的原因是我们的组织开始使用声纳的静态分析结果作为 KPI,而我的工作是降低数字。这是做任何事情的糟糕理由,但仍然是一个有趣的工程挑战....
我尝试的一种方法是抛出一个特定的RuntimeException
类,带有一个退出代码实例变量,并在外部范围内捕获它。这样,您就可以确定当您确实谋杀虚拟机时,您无论如何都处于堆栈的尾部......
public class Splat
public static final class Exit extends RuntimeException
private int exitCode;
public Exit(int exitCode)
this.exitCode = exitCode;
public static void main(String[] args)
try
wrappedMain(args);
catch (Exit e)
System.exit(e.exitCode);
public static void wrappedMain(String[] args)
if (args.length > 0 && "splat".equals(args[0]))
int code = (args.length > 1) ? Integer.parseInt(args[1]) : 0;
throw new Exit(code);
输出:
$ java Splat
$ java Splat splat
$ echo $?
> 0
$ java Splat splat 1
$ echo $?
> 1
> $ java Splat splat 2
$ echo $?
> 2
$ java Splat splat -1
$ echo $?
> 127
当然,这种方法有一些注意事项!这是一种奇怪的退出方式,任何不熟悉您的约束的人都会摸不着头脑。另外,如果有人稍后catch (Throwable t)
,那么你将无法退出!如果您在静态分析 CI 环境中工作,那么应该很快将其突出显示为更严重的违规行为!
【讨论】:
【参考方案2】:正如已经评论过的:当您等待批处理或 shell 中的某些代码时,您实际上是在等待程序完成,这意味着您的 java 程序退出,JVM 也是如此。唯一的方法是使用System.exit(code)
,就像你已经在做的那样。
【讨论】:
【参考方案3】:如果您在谈论进程的退出代码,那么System.exit(int)
是可行的方法,因为您希望整个进程退出,因此 JVM 也应该关闭。
但是如果你想向批处理或 shell 发送一些错误消息(不退出进程),那么你将不得不使用System.err.println()
。这将写入错误流而不是输出流。
【讨论】:
以上是关于System.exit 的替代方案,可以将错误代码发送到批处理或 shell的主要内容,如果未能解决你的问题,请参考以下文章
代码安全 | 第十八期:调用System.exit()存在安全漏洞