Sponsored Link •
Bill Venners: Another concern Anders Hejlsberg had about checked exceptions, which is a concern I've heard many people express, is scalability. He said:
In the small, checked exceptions are very enticing. With a little example, you can show that you've actually checked that you caught the
FileNotFoundException, and isn't that great? Well, that's fine when you're just calling one API. The trouble begins when you start building big systems where you're talking to four or five different subsystems. Each subsystem throws four to ten exceptions. Now, each time you walk up the ladder of aggregation, you have this exponential hierarchy below you of exceptions you have to deal with. You end up having to declare 40 exceptions that you might throw. And once you aggregate that with another subsystem you have 80 exceptions in your throws clause. It just balloons out of control.
James Gosling: I've almost never seen that
actually happen in large systems. One of the coping strategies I've seen for dealing with
that kind if situation is exception wrapping. If you have a subystem that might be hit with
hundreds of different exceptions, you can always take those exceptions and wrap them in
a new one. You can create a new exception and list other exceptions as their cause. Also,
the exception class hierarchy can help. For example, there are dozens of different
IOExceptions, but it's common to not declare that you throw the specific
subclasses. You just throw
But in general, when you are writing a declaration in a throws clause, it is good to try to be as specific as possible.
Bill Venners: Why?
James Gosling: Because it gives more information to the context about what exactly went wrong. That helps client programmers discriminate among the different sources of failure in their catch clauses.
Bill Venners: Have you seen the throw clause scalability problem in your visits out in the industry?
James Gosling: I've never seen issues where people have a gazillion items in their throws clause. Three, four, or five, maybe—and even those numbers are rather large. Almost always it's zero or one.
Bill Venners: I've found that many people don't seem to think about programming so much in terms of the interface as an abstract contract and the implementation as one way to implement that contract. They just think in terms of "the code." But the throws clause is part of the interface. If someone makes an implementation change that results in a method being called that throws a new checked exception, that doesn't mean that exception should necessarily appear in throws clauses up the call stack. If you automatically plop exceptions into throws clauses, you're letting the implementation drive the interface, instead of thinking about what the throws clause should contain at the abstract contract level.
James Gosling: That's a place where exception translation can be a
good thing. If you have something that's supposed to be reading a database, and
somewhere deep inside it, it could conceivably get a
MalformedURLException, it probably doesn't make sense to propagate
that outward as a
MalformedURLException. It's better to think about
what kind of exceptions are really a part of the interface, and not just an artifact of how
the underlying method was implemented. In the Java exceptions mechanism, exceptions
can have a reference to other exceptions as their cause. So you create a new
IOException, and you set its cause to this
MalformedURLException. And you bundle them together. That's been