Java – guideline on void methods that do not throw exceptions

coding-stylejavaprogramming practices

In our codebase I saw a method that is similar to following:

public void doSomething() {
    try {
        ...
    } catch (Exception e) {
        ...
        //log something
        ...
    }
}

The caller has no way to know if the method did what it is supposed to. Are there any general Java guidelines on not writing void methods that do not throw exceptions?

Best Answer

First of all this method is not unit testable.

There is nothing in the code you quoted which prevents it from being covered by unit tests.

The presence of try/catch is irrelevant:

  • You can test the situation where there is no error and check whether the side effects of this method correspond to the expectations.

  • You can also test the situation where an exception is produced, and ensure that the expected message is indeed logged (hopefully, the logging framework can be replaced with a mock.)

This means that you can get a 100% branch coverage despite the global catch of the exception. Talking about the global catch, this is not something you really want in your code base (unless there is a throw inside a catch), but this has nothing to do with unit tests.

This would apply as well if the method was catching only a specific exception, say FileNotFoundException, but there could be other exceptions thrown, such as StackOverflowException. You can then have three tests:

  • The ordinary situation with expected side effects,

  • The situation where FileNotFoundException is thrown and the expected log message is added,

  • The situation where StackOverflowException is thrown; any decent unit testing framework allows you to test that the exception is effectively thrown in a tested case (and the test will fail if the method doesn't throw the expected exception).

Are there any general Java guidelines on not writing void methods that do not throw exceptions?

By “do not throw exceptions”, I suppose you rather mean “catch all the exceptions”.

  • Catching exceptions has nothing wrong as soon as the method knows how to deal with the exceptional cases. For instance, a method which accesses the configuration file and encounters FileNotFoundException may fallback to default configuration instead, without reporting any exception to the caller. This is fine.

  • Catching exceptions globally (that is catch (Exception)) is slightly more problematic. Cases where methods are able to deal with any exceptional situation are very rare. There are still two exceptions:

    1. A method can catch any exception, and then throw the same exception (preferably without breaking the stack). This, for instance, enables logging: a method logs an exception, and then lets the caller deal with it.

    2. A method which is on top of the stack can catch any exception, because the choice is rather limited: either you catch the exception, or you let the program crash. The developers may prefer in this case to catch everything, even exceptions they can't deal with, and, for instance, present the user with a user-friendly dialog box which makes it possible to report the exception to developers' team.