Article Discussion
The Trouble with Checked Exceptions
Summary: Anders Hejlsberg, the lead C# architect, talks with Bruce Eckel and Bill Venners about versionability and scalability issues with checked exceptions.
46 posts on 4 pages.      
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: May 6, 2013 11:03 AM by Gregg
David
Posts: 3 / Nickname: malven / Registered: July 2, 2003 2:32 PM
Re: The Trouble with C,C#,C++ newbie's
August 27, 2003 5:07 AM      
> But what evidence is there that Java programs are,
> on the average, more robust than programs in every other
> language, because of checked exceptions?

Who made that claim? I believe the discussion was whether or not checked exceptions contribute to higher-quality programs, not whether Java is the "best language ever" specifically because of this one feature.

> I think you only get robust programs from hard
> work and extraordinary care, regardless of language
> features.

I disagree. Of course, hard work and skill are necessary, but different language features can have a huge impact on the amount of skill required to get programs to work reliably. As an extreme example, with enough care you could write a huge multi-tier application in assembler, but few programmers could do so, and it would take an inordinate amount of time.

I've been working in Java for over 8 years, and my experience with checked exceptions is that they are well worth the effort. Checked vs. unchecked was a huge debate when RMI was first released, because RemoteException was checked and many (including me) thought it shouldn't be. Jim Waldo, in particular, made a compelling case that it should remain checked, and many years later I'm glad he held his ground. In my view, the exceptions that a method can throw are as much a part of the contract as the value it returns.

In practice, the "explosion of checked exceptions" problem cited in the original article rarely occurs, so I think it is a bit of a red herring. However, I have seen many Java systems where the designers decided they disliked checked exceptions and made everything extend RemoteException. Almost without exception (<g>) this was simply because they thought having to deal with checked exceptions was "a pain" (meaning inconvenient). And in many of those cases it was a sympton of sloppy design or sloppy error handling in general.
Sanjay
Posts: 1 / Nickname: sdwarka / Registered: August 13, 2003 11:11 PM
Re: The Trouble with Checked Exceptions
August 28, 2003 4:23 AM      
Anders Hejlsberg says: The scalability issue is somewhat related to the versionability issue. 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've got 80 exceptions in your throws clause. It just balloons out of control.

We'd encountered situations like this in an RMI project.

We faced some of the issues Anders mentions with using checked exceptions and so we made a conscious decision to define a hierarchy of unchecked exceptions for the application. This is not to say we discarded checked exceptions altogether, we just used them as we saw fit.

We also needed to handle checked exceptions from the server side that were not application related. So we designed a wrapper for the parts that talked to the server that translated the non-application exceptions to application (mostly) unchecked exceptions. Yes, we did lose some information in the process but we moved ahead.

This way, we were able to achieve a reasonable balance.

Overall, you do run into some problems with checked exceptions and some other without, but wouldn't checked vs. unchecked be a matter of design decisions?
Cameron
Posts: 2 / Nickname: grom / Registered: July 21, 2003 6:10 PM
Re: The Trouble with Checked Exceptions
August 29, 2003 0:19 AM      
Take the following code as an example:
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
try {
  conn = DbHelper.getConnection();
  stat = conn.prepareStatement("SELECT * FROM addressbook");
  rs = stat.executeQuery();
  while(rs.next()){
    // print out name & email
    System.out.println("Name: " + rs.getString("name"));
    System.out.println("Email: " + rs.getString("email"));
  }
} finally {
  if (rs != null) rs.close();
  if (stat != null) stat.close();
  if (conn != null) conn.close();
}


All the database calls can result in a SQLException which are checked exceptions. At production time, this code should only fail if the database connection is lost or the database crashes. As a result of SQLException being a checked exception the above method will either have to declare to throw SQLException or wrap SQLException (which is most likely the better design choice).

So the problem with checked exceptions is that it forces the library user to handle the exception even if this isn't required. In the above code, we should not be catching exceptions from the query execution and result set retrieval since exceptions from these calls will most likely be from a coding error. Note however, part of this problem is due to lack of exception hierarchy for SQL exceptions.

Anyway, I still think checked exceptions are useful but they must be used with care. This is the problem with checked exceptions. They cause problems for the API user if they have been used where they should not have.

I think a good start for determining wether to use unchecked or checked would be Rod Johnson's rules in Chapter 4 of "Expert One-on-One: J2EE Design and Development" which you can get from http://www.wrox.com/books/sample-chapters/samplechapter_0764543857.pdf
Frank
Posts: 135 / Nickname: fsommers / Registered: January 19, 2002 7:24 AM
Re: The Trouble with Checked Exceptions
August 29, 2003 11:15 PM      
> All the database calls can result in a SQLException which
> are checked exceptions. At production time, this code
> should only fail if the database connection is lost or the
> database crashes.

Not really. The code can also fail if someone, unbeknown to your application, changes the database schema so that the specified relations and fields no longer exist. Of course, the question is, does it help us to know what went wrong when accessing the database? In the case of this simple query, it might not matter whether the DBMS was down, or a table changed. So, in this simple example, it might not matter whether SQLException is a checked exception.

> So the problem with checked exceptions is that it forces
> the library user to handle the exception even if this
> isn't required.

But it is required. The app should handle this exception. For instance, it might fail over to a backup database, etc. If a developer has to expect this exception (because it's declared by the JDBC API), that gives the programmer another chance to think and consider what remedies can be applied when the exception does happen.

> In the above code, we should not be
> catching exceptions from the query execution and result
> set retrieval since exceptions from these calls will most
> likely be from a coding error.

Or, again, a change in the system (ie. schema change). But in the case of an update, there can be a whole set of other reasons for SQLException to occur (ie. attempts to violate primary key constraints, incorrect data types, etc). Which brings us to....

>Note however, part of this
> problem is due to lack of exception hierarchy for SQL
> exceptions.

Which is why I think typed exceptions should be added to SQL. Currently, each DBMS generates its own error codes when SQL errors occur. For instance, if I try to do an insert with values that would violate primary key constraints, the DBMS might generate some error code. That code, in turn, bubbles up as an SQL Exception. What I'd really like to see is for the SQL language to have a typed exception hierarchy. For instance, it might throw a "IntegrityViolationException, " etc. Having these typed exceptions generated as part of SQL statements would really help database application development.

For instance, suppose you wanted to insert a customer record into a database table with a primary key of a customer's social security number. Currently, I'd have to write code such as:
try {
PreparedStatement st =
dbconnection.prepareStatement("select ssn from customer where ssn=?");
st.setString(1, customer.getSSN());
ResultSet rs = st.executeQuery();
if (rs.next()) {
//customer is already in DB,
//inserting would cause an SQLException
//just close db objects and return
} else {
//do the insert
st = dbConnection.prepareStatement("insert into customer ....")';
dbConnection.commit();
}
} catch (SQLException e) {
////
}

This is really bad code. I need to check first if the customer is already in the database - if I try to the insert and the customer is already in the database, I get an SQLException. But I can't tell whether the SQLException occurred because the DBMS went down, or because if the attempted integrity violation. So not having typed SQL exceptions renders SQLException itself more or less useless. What I'd like to see, instead, is something like:

try {
PreparedStatement st =
dbConnection.prepareStatement("insert into customer .....");
st.executeUpdate();
dbConnection.commit();
} catch (SQLIntegrityException e) {
///this is OK - the customer is already there, so do nothing
} catch (SQLConnectionException e) {
//this is not OK - fail over, or do some other recovery work here
}

But those different DBMS exceptions must originate from the database, as a result of the SQL statements. That can only happen if there is a standard hierachy of SQL exceptions defined by SQL itself.
Cameron
Posts: 2 / Nickname: grom / Registered: July 21, 2003 6:10 PM
Re: The Trouble with Checked Exceptions
August 30, 2003 2:21 AM      
>> All the database calls can result in a SQLException which
>> are checked exceptions. At production time, this code
>> should only fail if the database connection is lost or
>> the database crashes.
>
> Not really. The code can also fail if someone, unbeknown
> to your application, changes the database schema so that
> the specified relations and fields no longer exist. Of
> course, the question is, does it help us to know what went
> wrong when accessing the database? In the case of this
> simple query, it might not matter whether the DBMS was
> down, or a table changed. So, in this simple example, it
> might not matter whether SQLException is a checked
> exception.

But it does matter and that's my point. Since it is checked you either wrap it or pass it on by declaring to through SQLException. In a layer design, you would wrap the exception. In the example that I gave, although there could be a database schema change having to handle this is not reasonable. How often is this going to happen? The JDBC API designers think it is often. I don't. For example, in a standalone application where it is the only process accessing the database, there is a coding error if rs.getString("name") fails. This is the problem with checked exceptions, it makes assumptions about how you will use the API. In the case of my example, wrapping the exception adds no value but I don't want to throw an SQLException on the interface.

>> So the problem with checked exceptions is that it forces
>> the library user to handle the exception even if this
>> isn't required.
>
> But it is required. The app should handle this exception.
> For instance, it might fail over to a backup database,
> etc. If a developer has to expect this exception (because
> it's declared by the JDBC API), that gives the programmer
> another chance to think and consider what remedies can be
> applied when the exception does happen.

But I don't want to handle the exception. I want to tell the user that the database needs to be restarted and contact the system admin with a generic exception handler. Or maybe the database is an in-process database (eg. HSQLDB) and therefore this exception means that we should exit the system. A checked exception also doesn't ensure that I consider a lost connection, since it is possible just to shallow it. Checked exceptions don't stop lazy programming. And they can be annoying for those that take the time to think about their code.

Although checked exceptions do have a purpose. I just think SQLException is a prime example where it should not have been used. The Spring framework translate SQLException to unchecked exception. Plus it has an exception hierarchy so no dealing with vendor error codes.
Frank
Posts: 11 / Nickname: fmitchell / Registered: January 31, 2003 9:53 AM
Re: The Trouble with Checked Exceptions
August 30, 2003 4:02 PM      
Just my 0.02 Euros on this:

One of the prime problems with Java exception handling, in theory and in practice, is that there's no distinction between "coding errors" -- violated assumptions, internal resource exhaustion, etc. -- and uncommon but serious external conditions -- I/O errors, O/S signals, server-side errors, etc. Compounding this problem, many Java APIs wrap a whole class of implementations with some common -- and sometimes overly abstract -- layer.

Therefore, many APIs, like java.db and javax.jms, throw general exceptions on every single method call, just in case some implementation might have some internal or external error at that point. APIs indicate all errors, even easily avoidable ones, by throwing an exception. For example, an implementation may only allow a finite number of sessions or connections (SQL, JMS, whatever); only the message, and occasionally the exception class, could inform the user what happened ... unless it's been swallowed somewhere in an ill-written or empty catch clause by an annoyed developer.

Ideally Java would have a distinction between common and therefore checked external problems like IOException, and unchecked but documented Eiffel-style "contract" assertions of internal assumptions. It would also be nice if APIs considered a range of possible implementations and added queries to detect contract violations before they happened, and place exceptions only where unpreventable exceptions could happen: committing a transaction, sending a message, making an RMI or RPC call.
Andrew
Posts: 2 / Nickname: methusaleh / Registered: February 14, 2003 10:40 PM
Re: The Trouble with Checked Exceptions
September 7, 2003 10:24 PM      
What about a software language that can declare where an exception must be trapped?

Eg: throws IOException caughtby Caller, Classname, Main

Where Caller means the exception must be caught by the code invoking the method. Classname means that the exception will be unchecked until it reaches/passes through a specified class. Main could indicate that the application must at some point trap it. etc

I guess this could be extended to allow the thrower to specify at runtime who can actually catch the exception.

Also, as stated in the prior post this could also be added via 'design by contract' allowing both the caller and method to force exception checking.

(Hope I have understood the whole issue properly)
Kirthi
Posts: 1 / Nickname: kirthi / Registered: September 24, 2003 0:34 AM
Re: The Trouble with Checked Exceptions
September 24, 2003 4:41 AM      
I agree. Also this is something that has been raised a little too late.
Noop
Posts: 2 / Nickname: dleuck / Registered: October 2, 2003 6:45 PM
Re: The Trouble with Checked Exceptions
October 2, 2003 11:08 PM      
> Nowadays exceptions seem to have removed return values as
> a method of indicating success/failure or an unexpected
> event. (In some ways I guess its does this cleaner and
> simpler.) However I tend to restrict the use of
> exceptions for implementing 'exceptional use cases' and
> stick with return values to handle errors and such. Is it
> possible that people are just over using exceptions or
> using them for the wrong purposes? (Especially with
> respect to the versioning problems)

Returning errors is considered an antipattern. It is very bad design for a number of reasons (example - its easy for the programmer (API user) to accidentally handle the error as a an "answer" rather than an "error". Many famous computer disasters were caused by this practice. It has been generally agreed that signals (ex: Exceptions) should be used instead.
Noop
Posts: 2 / Nickname: dleuck / Registered: October 2, 2003 6:45 PM
Re: The Trouble with C,C#,C++ newbie's
October 2, 2003 11:10 PM      
> However, I have seen many Java systems where the
> designers decided they disliked checked exceptions
> and made everything extend RemoteException.

I think you mean "RuntimeException"

BTW - I agree with you 100%. Exceptions are an important part of the API contract.
Gregg
Posts: 28 / Nickname: greggwon / Registered: April 6, 2003 1:36 PM
Re: The Trouble with C,C#,C++ newbie's
October 3, 2003 8:49 PM      
> > However, I have seen many Java systems where the
> > designers decided they disliked checked exceptions
> > and made everything extend RemoteException.
>
> I think you mean "RuntimeException"

I am sure that he means RemoteException. It is a common thought in RMI programming that you've already sprinkled 'throws RMIException' at the end of all you methods in your Remote interface, so rather than add yet another Exception to that, just extend RemoteException, or wrap the exception in RemoteException.

The modifications to add a cause to exceptions was brilliant. Calling initCause() with an Exception that you can't pass up the ladder makes it much easier to wrap your implementation in a well devised collection of Exceptions, and not loose any information about where the real problem occured at.

Checked Exceptions are a vital part of any API that interfaces with something that the calling code has no control over. If I am opening a file, using the network, making and RPC call etc, it will be impossible for me to guarentee the outcome with software. Thus, the Exception tells me that something unexpected and impossible (a relative term without historical perspective) to deal with has occured, plain and simple.

My initial thought when reading this piece was, wow, here's someone else who works for that company that is selling the software that is costing people the most time, money and agony (due to data loss). He thinks that handling exceptional cases is not that important, or at least not important enough to require rigor. Perhaps buffer overruns are not exceptional cases after all, and we should just consider them a part of life... and all the virui that have come from them?

I too wonder about the conflict of this position versus the virtual method position...
Gregg
Posts: 28 / Nickname: greggwon / Registered: April 6, 2003 1:36 PM
Changing Exceptions in the Life Cycle
October 6, 2003 2:12 PM      
I was thinking about this issue some more. One of the vital capabilites of Java is downloaded code. In Jini applications (and simple RMI too), you can easily exploit downloaded code to make changes to the API. As an example, consider an interface with a method that does work on the server. In the initial version, you just passed a key value to select the type of operation and the server did it locally and returned the result.

In the next version of the client, you want the server to also provide a proxy connect operation to some other machines for a new class of keys, and if it can't connect, the client needs to tell the user, or make some other decision. The important business is that if the old client doesn't (and can't because of implementation) pass the new keys, it can never see the new class of exceptions!

So, you need to add to the throws clause to include the exceptions that are associated with the remote work.
public interface MyInterface extends Remote {
    public void meth1( String type ) throws RemoteException;
}

is the old version of the interface and method. In the new version, you should make the changes in a backward compatible way. You can code this as
public interface MyInterface extends Remote {
    public void meth1( String type ) throws RemoteException;
    public void newMeth1( String type )throws IOException,IllegalArgumentException;
}

Now, the next part is the tricky part. You want to make the server have this new functionality, but keep the client interface backward compatible with the old client.

So, you use the delegate pattern to create a smart proxy that allows the new server API to exist, but hides the old method and defers to the new method.

public class MyInterfaceSmartProxy implements MyInterface,java.io.Serializable {
    MyInterface del;
    public MyInterfaceSmartProxy( MyInterface delegate ) {
        del = delegate;
    }
    public void meth1( String val ) throws RemoteException {
        try {
            del.newMeth1( val );
        } catch( RemoteException ex ) {
            throw ex;
        } catch( IOException ex ) {
            log.log( Level.SEVERE, ex.toString(), ex );
        }
    }
}


Now, in the server, where you would normally register your proxy with the LUS or RMIRegistery, you would instead pass
new MyInterfaceSmartProxy( exportedObject ), where exportedObject was the existing proxy.

Now, you have a versioned solution and the user always gets the correct solution after the server is upgraded because you are exploiting downloaded code to manage versioning...
Damon
Posts: 1 / Nickname: doremon / Registered: February 7, 2004 9:24 PM
Re: The Trouble with Checked Exceptions
February 8, 2004 2:36 AM      
I can't say I'm qualified as I don't do super big systems (thanked goodness). For small interactive applications, program throws an error, usually it's appropriate to just display it to the end-user.

But let's say we have large concurrent systems. In some cases, the errors could be due to concurrent or unknown events that results in denial of certain resources. Due to business requirements (an example, last item in the online store but just got booked by a VIP whom may or may not want it, business rule says don't tell online shoppers that it's unavailable) or some jinx (e.g. weird network problem), application detect error at runtime but don't know the exact cause or can't reveal...what do you do?

Throwing an exception may not be the important thing here but the finally part is (e.g. tell shopper that their other items are processed and ready for payment but not that last item due to whatever cook up reason). Well, i don't know the right answer for this as well....hmmmm, still pondering.
Matthew
Posts: 1 / Nickname: darkfrog / Registered: February 10, 2004 5:51 AM
Re: The Trouble with Checked Exceptions
February 10, 2004 10:58 AM      
After reading this article I can't help but wonder why you didn't state that checked exceptions are optional in Java? It is up the coder to decide if they want checked or unchecked Exceptions. If you extend RuntimeException it is automatically unchecked. For example, how many times have us Java coders had to deal with NullPointerExceptions, but never actually had to put a catch block in our code? It's just one example of an unchecked exception in Java. Granted, there are several checked exceptions in Java that you are required to deal with if you wish to use that Object, but the designer of that Object thought it necessary to deal with that exception. If you don't like it, create your own Object that does the same thing and use unchecked exceptions.

As for this debate in general, I think it's laziness that makes people disagree with checked exceptions as a whole. They are an amazing feature and quite useful to a good programmer. I realize they are often abused, but that's the problem of bad coding rather than bad language implementation.

Thanks,

Matthew Hicks
darkfrog@pyramex.com
Benjamin
Posts: 1 / Nickname: benthere / Registered: February 10, 2005 7:16 AM
Re: The Trouble with Checked Exceptions
March 19, 2006 1:11 PM      
> This argument sounds almost identical to the one used
> against languages (such as Python) that don't use compile
> time type checking. That being the case, then the reposte
> will also be similar... test driven development, if done
> properly, should be as effective in dealing with unchecked
> exceptions as it is in dealing with untyped variables.
>
> Poor programmers will always cause problems.

This argument doesn't account for the fact that we will always have poor programmers. Each of us was, at one time, a 'poor' programmer (no matter how short we imagine our visit with this stage).

The extent to which languages and tools coerce good practices with minimal negative impact to advanced programmers is particulary beneficial to the new-to-intermediate level programmer. In turn, this is beneficial to everyone who will inevitably have to fix a bug or hike through their ragged code path.
46 posts on 4 pages.