Discussions

General J2EE: Exception Bloat ?

  1. Exception Bloat ? (6 messages)

    Hi,

    I am working on a fairly simple web based application, (using JSP's, Servlets and JDBC).

    As the project has progressed I have realised that my backend code, especially the DAO/persistence code, has a lot of the following in it. (please see example)


    try{

        //try to save the object

    } catch (OneTypeOfException ex) {
        throw new SaveException(ex.toString());
    } catch (AnotherTypeOfException ex) {
        throw new SaveException(ex.toString());
    } catch (SQLException ex) {
        throw new SaveException(ex.toString());
    }

    I also have lots of exception classes, at the moment 3 per DAO object (one for a save exception, one for a read exception and one for a delete exception).

    I thought this was ok until I read some comments regarding the code used in the new pet store comparison.

    Some of the guys in that discussion specifically criticised this kind of code.

    Is this really bad ?

    And if so what would be a better approach to exception handling ?

    Keith Bishop

    Threaded Messages (6)

  2. Exception Bloat ?[ Go to top ]

    One thing that sucks about Java is that there's no "NonRuntimeException", and because of this, your code has to look the way it does. I've found that most of the time when catching exceptions (especially in low-level code), I'm usually wrapping the caught exception in another higher-level one, because usually I don't care if I got a NamingException or a RemoteException (i.e. it doesn't affect what happens in those cases). What's more annoying about Java is that you cannot handle exceptions like in C++, where you can do stuff like:

    catch ExceptionType1
    catch ExceptionType2
    catch ExceptionType3
    {
      // common handling code
    }

    (sorta like what you can do with a switch)

    So, what I tend to do when I need to create exceptions is that I keep them coarse grained, and then use verbose messages in them. So, for your example, I might create a "PersistenceException", and whenever I throw it, use a message for what the problem was. Because, all you ever need from the exception is a description of what happend and the stack trace, and you only look at that if something majorly screws up and you need to debug (i.e. NOT for normal program flow during normal conditions).

    Really, the only reason to have difference exception classes is if you need to do something different depending on the exception, and I find that I generally don't need to. IF you DO want them, put them in an inheritance hierarchy so you can catch the base exception if you want, or catch them inidividually.

    Now, some people just get lazy and do

    try
    {
      // whatever
    }
    catch (Exception e)
    {
    }

    But that sucks, because you don't want to catch RuntimeExceptions (and this is why it would be nice to have a NonRuntimeException). I guess you coudl always do:

    try
    {
      // whatever
    }
    catch (Exception e)
    {
      if (e instanceof RuntimeException)
        throw e
      else
        // handle it
    }

    But that seems kinda cheesy.

    I think the Exception class hierarchy in Java is just badly designed, and so it requires all this nastiness (this is probably a big reason that the BusinessDelegate pattern exists).
  3. Exception Bloat ?[ Go to top ]

    I sometimes use this pattern:

    try {
      ...
    } catch (RuntimeException ex) {
      throw ex;
    } catch (Exception ex) {
      ...
    }

    It works because Java will try exception one afteranother and choose the clause that matches first.

    Another thing to remember is that if you want to catch all exceptions, i.e. java.lang.Throwable, then you should make sure to pass Error to the caller. Error exceptions are *hard errors* that you generally should not try to recover from. RuntimeErrors might be recovereable one way or another...

    try {
      ...
    } catch (Error ex) {
      throw ex;
    } catch (Throwable ex) {
      ...
    }

    Cheers,
    Kresten
    Trifork J2EE Team
  4. Exception Bloat ?[ Go to top ]

    Keith, I think this kind of code is a serious problem.

    The orthodox approach to exception handling in Java produces code bloat that *is* a problem. I think the solution is to distinguish between application exceptions and fatal exceptions. An application can sensibly catch an application exception. A fatal exception is unrecoverable.

    I advocate making application exceptions checked exceptions, and fatal exceptions runtime (unchecked exceptions). This tends to reduce code bloat enormously. You *can* catch the runtime exceptions if you want, but don't need to. The servlet container or EJB container will catch them if you don't. But the compiler will still make you catch exceptions you can handle. The kind of catching and rethrowing you illustrate (which is used in lots of projects) adds little value and a lot of potential for mistakes. For example, your code example loses the stack traces.

    Java is the only language in which checked exceptions are the norm. C++ and C# don't have the concept of checked exceptions. Bruce Eckel, author of the classic "Thinking in Java", now questions why Java needs checked exceptions. I wouldn't go this far, but I think they are overused.

    In my new book, Expert One-On-One J2EE Design and Development, I talk in detail in chapter 4 about exception handling. In chapter 9 I look at exception handling in data access objects, including how to ensure that business objects aren't tied to the underlying data access technology, such as JDBC or entity beans. There's a thread on this book here.
  5. Exception Bloat ?[ Go to top ]

    Well, the problem is even if you do not design your own exceptions, you are still forced to write code similar to what Keith has posted. Most dealings with EJBs involve RemoteException, CreateException, RemoveException, and/or SQLException. You can't just let these be thrown by every method in your system. YOu have to convert them to a common higher-level exception. Usually, I will make an exception class for this, based on how EJBException works (i.e. it wraps an exception, thus preserving the stack-trace), but it is still mostly unavoidable.

    I do agree that it's a pain in the ass, and adds little value to the code. I think that if they were going to have Checked exceptions, there should've been a CheckedException class that is a sibling to RuntimeException (both extending Exception), so you can just catch blanket CheckedException if you care, and otherwise, everyone else throws it.
  6. Exception Bloat ?[ Go to top ]

    As Dave says, it's necessary to catch checked J2EE API exceptions such as CreateException and rethrow. Whenever I use EJB I use a client-side Business Delegate that conceals such exceptions from other application code. When such exceptions are deemed fatal, I throw an unchecked exception, that can preserves the stack trace and which application code can choose to catch if it's interested. This approach also has the advantage that only the Business Delegate interface's implementation must deal with EJB-specific exceptions. This means that we can choose to use EJB or not on a case-by-case basis without affecting code throughout the system.

    Regarding JDBC, I think it's a pain that SQLException is checked. As JDBC is also a low-level API that's hard to use correctly, I use an abstraction layer that makes JDBC easier to work with (no more need for finally blocks) and throws meaningful *unchecked* exceptions. This means that business objects can distinguish between problems without being tied to JDBC (the same exceptions can also be used by other Data Access implementations) and never need to catch exceptions they can't handle. Chapter 9 of my book discusses this, and the source code with the book includes all the JDBC abstraction code and exception classes.
  7. Exception Bloat ?[ Go to top ]

    For what it's worth, we have pretty much sworn off (1) checked exceptions and (2) catching exceptions at all, except at the top-most levels of code (e.g. user interface manager). It has made everything SO much nicer. No need to put try/catch blocks everywhere. No need to wind your way through a twisty little maze of sub-Exceptions (except of course that some of them are sub-Throwables).

    We only use checked exceptions for cases where there is some SPECIFIC exception that needs to be caught by a caller. In general, callers never do catch (Exception) - if method X throws exceptions Y and Z, we catch Y and Z. (Of course, it would be handy to be able to say

    try {
      foo ();
    } catch (MyFirstException y, MySecondException y) {
      y.printStackTrace ();
    }

    but I don't see that forthcoming ...