I have a set of error codes in my java application. Currently I'm using System.exit(code); to return error codes from the application to external applications.
Is there any alternatives of System.exit as using this is bad practice because it may shutdown the entire JVM.
3 Answers
I have shared your experience in the past, and tried to engineer out System.exit(). One possibility is to leave a RuntimeException uncaught and you will return 1 to the shell, but ultimately if you want any more versatility than that (and don't want an ugly stack-trace polluting your output), you must have at least "one" call to System.exit().
public class Splat {
public static void main(String[] args) {
if (args.length > 0 && "splat".equals(args[0]))
throw new RuntimeException("splat");
}
}
Output:
$ java Splat
$ echo $?
> 0
$ java Splat splat
> Exception in thread "main" java.lang.RuntimeException: splat
> at Splat.main(Splat.java:9)
$ echo $?
> 1
My reason for doing this was our organisation started using static analysis results from sonar as a KPI and it was my job to get the numbers down. It's a terrible reason for doing anything, but an interesting engineering challenge nonetheless ....
An approach I tried was throwing a specific class of RuntimeException, with an exit-code instance variable, and catching it at the outer scope. That way you can be sure that when you do murder the VM you're at the tail of the stack anyway ...
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);
}
}
}
Output:
$ 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
There are caveats to this approach of course! It is a bit of an odd way to exit and anybody unfamiliar with your constraints will scratch their head. Also, if somebody does catch (Throwable t) later on, then you wont be able to exit!!! If you are working in a static analysis CI environment then that should be quickly highlighted as a more grievous violation!
Comments
If you are talking about the exit code of a process then System.exit(int) is the way to go since you want the whole process to exit and so the JVM should shutdown as well.
But if you want to send out some error messages to the batch or shell (without exiting the process) then you will have to use System.err.println(). This will write to the error stream instead of the output stream.
System.exit()is a "bad" way to exit your application. Many static analysis tools highlight it as such. Reason being is that you may not have cleaned up everything before exiting. Also it can be quite bewildering for a user. To my mind the only reason you "should" ever use it (in normal circumstances) is if you want to return an exit-code to the shell.System.exit()it can cause problems for people wanting to use your code in a larger application. Just likegotoit may be used as a short-cut to end your application without cleanly unwinding your stack. In the end, if somebody wants to use your code they'll not only have to eliminate all yourSystem.exit()but they may have to restructure your code too!