views:

125

answers:

4

I am considering a design where all fatal exceptions will be handled using a custom UncaughtExceptionHandler in a Swing application. This will include unanticipated RuntimeExceptions but also custom exceptions which are thrown when critical resources are unavailable or otherwise fail (e.g. a settings file not found, or a server communication error). The UncaughtExceptionHandler will do different things depending on the specific custom exception (and one thing for all the unanticipated), but in all cases the application will show the user an error message and exit. The alternative would be to keep the UncaughtExceptionHandler for all unanticipated exceptions, but handle all other fatal scenarios close to their origin.

Is the design I'm considering sound, or should I use the alternative? What is the typical approach used for handling fatal exceptions?

A: 

It would be more straight-forward to wrap the logic of the main method in an try catch block; e.g.

public static void main(String[] args) {
    try {
        // everything happens here
        System.exit(0);
    } catch (SpecificException ex) {
        ...
    } catch (AnotherException ex) {
        ...
    } catch (Throwable ex) {
        // deal with anything else.
        ...
    }
    System.exit(1);  // tell the world that we failed.
}
Stephen C
Thanks for your reply. The problem with that is it won't catch exceptions that happen on the Swing event dispatch thread. However, I'm more interested in whether the design of having a top level exception handler (where I'm creating some of the exceptions) is wise.
Stephen Swensen
+2  A: 

Usually, it is hard to find a good exception handling strategy. Every approach has its drawbacks. In particular, Yours is good in some sense (a centralized location for handling failures) but suffers from this flaw:

The exception handler you're describing will have special handling for each possible exception. Over time it will become a focal point of your application: every time you add new functionality you will also need to add exception-processing logic to your handler. This means that:

  1. The handler is highly dependents on other parts, a change in impl. of some functionality is likely to trigger corresponding changes in the handler. You will need to be careful in keeping these two in sync.
  2. The handler has poor coherency (has many reasons to change) - it contains the intersection of all features of your app.

Another problem is error recovery. After an exception is thrown (and a some notification is presented to the user), the user want to continue using the application. This means that if your code started modifying the internal data structures and then stopped due to exception, you will need to undo these modifications (or at least get the data structure back to a workable condition) before you allow additional interaction of the user. Achieving this requires a new thinking about the way your data is organized. One possible solution is to DB transactions. On the other hand, this kind of representation is more complicated than plain-old data structures so you need to weigh it against the needs of your app (is it a toy/prototype?)

Itay
Thanks for your feedback. The flaw you describe is what I was fearing, and hearing you spell it out is very helpful (I will probably abandon the centralized approach). I'm going to leave this question open for now, to welcome others input, but will come back tomorrow and likely mark yours as the answer (unless some other super compelling answer shows up).
Stephen Swensen
+1  A: 

I have successfully used a mix of local handling and a centralized handling in a large Swing application. The centralized handler only handled I think two or three specific types, and all uncaught exceptions. It's been a while so I don't remember all the details, but we ended up with a centralized handler that took care of two or three specific types of exceptions and all uncaught exceptions.

We used local handling where ever possible, but also defined something like ErrorMessageException that could be thrown also from background threads that did not interact with the UI. This exception had a specific handling in the central handler. We didn't think this is the most beautiful solution available, but it was simple and easy and worked well.

Any uncaught exceptions were handled as "general error" or something similar. Worked well, and of course we tried to release code that did not cause any unhandled exceptions. However, this was very helpful feature in testing.

With this approach the centralized handler was easy to maintain and did not grow unexpectedly. Also we did not see any symptoms of tight coupling, quite the opposite actually.

fish
+1 Nice, I appreciate the real-world experience.
Stephen Swensen
A: 

If you have a multithreaded application (like most Swing apps) you might want to consider sending the exceptions to a central exception-handling thread through some async queue.

Little Bobby Tables