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()存在安全漏洞

相当于 System.exit(-1) 的 Kotlin Native

VS2013 中 HTMLhelp 的替代方案

使用 System.exit(0) [重复]

查看 Unix 中的 java 退出代码

java停止运行怎么解决