Sweetohm

Michel Casabianca

Here is a short document that describes my view on exceptions management in Java command line applications.

This is a quite different from the case of a library where you should type the exceptions you throw so that receiver will be able to take appropriate decisions.

This is also quite différent for web applications where you won’t catch exceptions in main() but in a place where you will be able to return appropriate status code. You would also probably throw exceptions that would contain status code to return.

Exception catching policy

You only catch an exception in these situations:

  • You can fix the cause of the exception
  • You throw another exception with catched exception as cause (you pass catched exception as second argument of the raised exception)

You never catch an exception if you can’t fix it or if you don’t throw another one. This code is forbidden:

try {
    // do something
} catch (Exception e) {
    System.out.println("help!");
}

Exception propagation policy

An exception that is not fixed must be propagated to calling code. You can do it by declaring the exception in the method signature. You can also throw a new exception containing raised exception as the cause.

For instance, if an exception is raised reading configuration file, you might write following code:

try {
    // load configuration file
} catch (Exception e) {
    throw new ManagedException("Error loading configuration file", e);
}

The message of the raised exception will clarify the error and the cause exception (passed to the constructor of the raised exception) will specify the cause of the error (file not found for instance).

Managed exceptions

You should print a stack trace only for unexpected exceptions. For instance, when configuration file is not found, it is not necessary to print a stack trace, an error message is far better.

In this case, you should throw a managed exception that will carry the error message, is in the example above.

A ManagedException class could look like this:

public class ManagedException
    extends RuntimeException {

    public ManagedException(String message) {
        super(message);
    }

    public ManagedException(String message, Throwable cause) {
        super(message, cause);
    }
}

Propagated exceptions management

Exceptions that are propagated to calling method must be processed somewhere. There should be only one place in an application where you process these exceptions. This code should look like:

try {
    // body of the application
} catch (ManagedException e) {
    if (e.getCause() != null) {
        LOGGER.error(e.getMessage() + " : " + e.getCause());
    } else {
        LOGGER.error(e.getMessage());
    }
    System.exit(1);
} catch (Exception e) {
    LOGGER.error("Unexpected error", e);
    System.exit(2);
}

Best place for this code is in main() method of the program.

Any feedback welcome (in comments)!

Enjoy!