Eric Burke claims that check exceptions introduce implementation dependencies into your code:
Because the DAO throws PersistenceException, the next higher layer of your application must deal with it. This is a big problem, because this means your business logic now has persistence framework dependencies. What if you want to write a DAO that uses direct JDBC instead? Or you want to switch to Hibernate? Oops…every layer of your app depends on the old persistence API thanks to checked exceptions.
Here’s his sample code:
public class DefaultCustomerDao implements CustomerDao {
public Customer findById(Integer customerId) throws PersistenceException {
...do something with the persistence framework that throws PersistenceException
}
}
He claims that the calling code now has to know about PersistenceException, and that’s bad. He’s right on the surface of course, but I think he misses a point: the calling code already has to know about details of the persistence mechanism: it has to know about findById(), which in turn is a part of CustomerDao. (These classes are part of his fictional persistence framework that could be switched out for some other framework).
If you’re already dependent on CustomerDao and findByID() for your calling code, then adding a dependency on PersistenceException is not much worse. Thanks to the Law of Leaky Abstractions you’re probably more dependent on your persistence framework for more than APIs anyway; your code will almost certainly be structured around the API’s paradigm, so switching to another one will involve a lot of work regardless of whether it uses checked exceptions or not.
What you can do to minimize all this is to abstract your persistence mechanism behind a new API and paradigm that you control. This API would then call the API that does the actual work. You could swap out implementations of your API as you see fit (although due to the leaks it will still involve some recoding).
Under such a system, whether a framework uses checked exceptions is entirely irrelevant; it’s completely up to you whether you want to use them or not:
- If it does, and you do, you can wrap its exceptions in your own, and gain interface independence.
- If it does, and you do not, you can catch them in your API and then implement your own error-handling system (RuntimeExceptions or error codes).
- If it does not, and you do, then you can work with its error-handling system (again, RuntimeExceptions or error codes) and throw your own checked exceptions as appropriate
- If it does not, and you do not, then you can possibly get away with doing absolutly nothing (ie: letting the RuntimeExceptions propagate). You still have the same options as in point #2 as well.
I believe that your “real” code should be (at least) one abstraction away from any third-party library or framework, whenever possible. This gives you the least dependence on it should you want/need to change it down the road. Depending on the maturity of the library and the prevalence throughout your project, wrapping it in an abstraction layer is usually well worth the additional work: you gain flexibility (which is crucial in any project) and can “fix the problems” (as you define them) in the API as you go along.
(Perhaps surprisingly, this is my first Java-related post. What’s surprising is that I do Java for a living; I guess that I talk enough about it during the day that I don’t feel much need to blog about it on my own time

