http://harry.hchen1.com Harry has posted 1 posts at DZone. View Full User Profile

On Java Exception Handling

08.12.2008
| 22674 views |
  • submit to reddit

I came across a series of blog posts by Daniel Pietraru that deal with the use of exceptions in Java programming — I love it. The exception framework in Java provides a means for programs to signal and handle errors and other exceptional events. It’s not difficult to write code to throw and catch exceptions in Java. But, properly use exceptions in Java programs is not well understood by many developers.

There are three types of exceptions in Java: checked exceptions, unchecked exceptions and error exceptions. Checked exceptions are all exceptions that subclass from the java.lang.Exception class. When a method throws a checked exception (e.g., IOException), the client code must handle the exception by either defining a try-caught block or delay the exception handling by propagating the exception event up to a higher level code.

Unchecked exceptions are all exceptions that subclass from java.lang.RuntimeException. Unlike the checked exceptions, when a method throws unchecked exceptions, the client code is not required to define explicit code to handle the exceptions — e.g., NullPointerException.

Error exceptions, the last type of exceptions in Java, are all classes that subclass from java.lang.Error. These exceptions indicate serious problems that a reasonable application should not try to catch. For example, the exception java.lang.VirtualMachineError indicates the JVM is broken or has run out of resources necessary for it to continue operating. Developers rarely need to throw error exceptions or write codes to explicitly hand error exceptions.

When designing a Java API that throws exceptions, how should you choose to throw a checked exception and an unchecked exception? Daniel discussed this in Exceptional Java - Exception design relatively. Answers to this question is also described in Joshua Bloch’s Effective Java.

The basic guideline:

  • Throw checked exceptions if the problems can be reasonably recovered in the client code.
  • Throw unchecked exceptions to indicate programming errors (e.g., bugs in the client code and mistakes by a careless programmer).

Sometimes it’s difficult to draw a black-and-white between which exception to throw given a specific exceptional condition. It’s really up to the developers to decide. Exception handling in Java if use properly can greatly improve software quality. It’s definitely valuable for developers to think about exception handling design in an early stage of their software development cycle.

Published at DZone with permission of its author, Harry Chen.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

D'Arcy Smith replied on Sat, 2008/08/16 - 5:30pm in response to: Casper Bang

[quote=cbang]

> We are talking about exception handling in Java.

lol If you are unwilling to compare to other practices and current state-of-the-art, then you might as well stop discussing these issues with the community.  I ask again, why not simply treat a "checked exception" as a warning condition? That way, prototyping (one extreme) can focus on the primary code path while mission critical implementatins (the other extreme) can treat every minute warning as a show stopper?

And remember, as good software developers we program into a language, not in a language. (Steve McConnel)

 

[/quote]

 In the same post you are replying to:

"And yes I have used other languages with other exception handling schemes.  I personally liked checked exceptions."

If you are going to ignore what I say then there is little point to trying to have a conversation.

It is a bad idea to try to "go against the flow" and program Java like you would something else, say Smalltalkm just as it is a mistake to try to treat another language like Java.  Each language has conventions, practices, idioms, etc... 

And, as a counter argument, how many production C++ programs have a catch(...) block that has wound up hiding bugs.  I know of a number of them.  They all have developers spending a significant amount of time when something goes wrong trying to figure it out - the same sort of thing doesn't happen in Java with checked exceptions (unelss you go out of your way to ignore them with empty catch blocks).

Tim Boudreau replied on Sun, 2008/08/17 - 2:02am

This discussion has seemed to boil down to a "checked exceptions are evil" camp, and a "checked exceptions improve robustness camp."

Let's back up a second.

What does a checked exception do?  What is it for?

It is for communication.  To the developer.  It communicates that a particular kind of failure can occur in a block of code.

With checked exceptions, you know all of the places in your code that failure can occur.  With unchecked exceptions, you don't.

How much of the objection to checked exceptions is objection to the bulky syntax of them, and the issues that causes for code readability, and how much is really about the fact of their existence?

For certain kinds of programming, checked exceptions are a necessary and good thing.  If your code controls a piece of machinery and recovering means knowing exactly how the thing failed, checked exceptions are your friend.  In the constructor of a URL they're aggressive, premature validation (only useful if you're writing, oh, say, HotJava :-)).

Casper Bang replied on Sun, 2008/08/17 - 10:13am in response to: D'Arcy Smith

I fail to see how I ignore what you say. Rather, I was simply asking about your position on my "have your cake and eat it too" suggestion in turning a checked exception from a "you MUST handle this exception, I don't care what you have to say" into a "you really AUGHT to handle this exception, for your own good". It should after all be a non-breaking change and get rid of this kind of code:

    try{
        is = new FileInputStream(...
);
    }
   
catch (FileNotFoundException ex){// If this happens, it's a programming error!
    }
   
finally{
       
try{
            is.close();
        }
       
catch (IOException ex){ // This can never happen. Period!
        }
    }

And I disagree with "going against the flow". Many patterns, idioms and convensions are not set in stone but tend to change over the years when applied in the real world. If you notice for instance since the inception of Java it's generally considered wrong how:

The JRE is littered with singletons

Objects are mutable by default

Classes are open to inheritance by default

Finalizers are used as destructors

...it's a long list.

Tim Boudreau replied on Mon, 2008/08/18 - 3:45am in response to: Casper Bang

Great points!  There is a lot of community knowledge out there about what works and doesn't work, which has only been gained by years of experience doing production code in Java, and none of these things which we know intuitively were obvious when the JDK was born.  When I do API design talks, I often feel as if mainly what I'm doing is encouraging people to unlearn patterns they're going to see but which have proven harmful in practice.  The oldest and largest proving ground for both what does and does not work is the JDK itself, simply because a lot of it is the oldest Java code that exists;  the challenge is to teach new developers designs that avoid now-known anti-patterns.  

D'Arcy Smith replied on Mon, 2008/08/18 - 3:00pm

catch (FileNotFoundException ex){// If this happens, it's a programming error! No it is not a programming error. The programmer could have checked that the file exists, and then when it is to be opened it has been deleted from the system by another program or the user, or the nfs mount went away, etc... there are so many things that can happen that are outside of the programmers control. catch (IOException ex){ // This can never happen. Period! I have never actually looked into it, but again what happens if the file is opened over nfs and then the nfs mount goes away before the file is closed, and the next action that the program takes once the nfs mount goes away is to call close? I do agree with you that after 13 years of Java programming I still have no idea what to do if close throws an IOException, and I still have yet to see it happen. Unfortunately it is not a programmer error it is an external error. ..darcy

phil swenson replied on Mon, 2008/08/18 - 5:11pm in response to: D'Arcy Smith

so what would you do if you encountered a FileNotFoundException or for that matter a SQLException?

how does a checked exception improve the situation over letting it bubble up and be handled generically by the top level thread?

 

another question:  if you have a method processFinder.getCurrentProcess() that is used say 400 places throughout your code and you decide to add a ProcessNotFoundException to this method... how do you do it? How do you handle the potential exponential implications of this exception?

Casper Bang replied on Mon, 2008/08/18 - 5:03pm in response to: D'Arcy Smith

> No it is not a programming error. The programmer could have checked that the file exists

See here's where the capture of intent breaks down. If I included a resource file in my program that is suppose to be there, then for all practical purposes, the scenario I described cannot happen. And IF it happens, I have messed up my build script and indeed then it's a programming error. That's why I am against checked exceptions, not for the general idea of expressing assertions but because they so often lure me into what's ultimately irrelevant paths of execution when I really want to be focusing on the primary path.

I don't really have much more else to say on the issue, except to point out that Effective Java Second Edition now contains an item (59) warning against the danger of checked exceptions, and also contains an idiom for working around them by the use of a state-testing method (basically breaking the assertion and execution up in two steps).

D'Arcy Smith replied on Mon, 2008/08/18 - 5:28pm in response to: phil swenson

"phil swenson replied on Mon, 2008/08/18 - 6:11pm in response to: darcysmith

so what would you do if you encountered a FileNotFoundException or for that matter a SQLException?

how does a checked exception improve the situation over letting it bubble up and be handled generically by the top level thread?

 another question:  if you have a method processFinder.getCurrentProcess() that is used say 400 places throughout your code and you decide to add a ProcessNotFoundException to this method... how do you do it? How do you handle the potential exponential implications of this exception?"

You are not supposed to change a public interface (by that I mean API).  This is why things like LayoutManger2 exist.  Once an API is public you should not be changing the signature.

That being said, things to change over time, especialy in internal APIs (public in the above doesn't mean public to the general world, it means public to the class/interface).

 If you make such a change then you would need to add 400 catches anyways, unless you like your programs crashing, but now you don't have the safetly of the compiler telling you that there were actually 401 places to chage it.

..darcy

D'Arcy Smith replied on Mon, 2008/08/18 - 5:46pm in response to: Casper Bang

[quote=cbang]

> No it is not a programming error. The programmer could have checked that the file exists

See here's where the capture of intent breaks down. If I included a resource file in my program that is suppose to be there, then for all practical purposes, the scenario I described cannot happen. And IF it happens, I have messed up my build script and indeed then it's a programming error. That's why I am against checked exceptions, not for the general idea of expressing assertions but because they so often lure me into what's ultimately irrelevant paths of execution when I really want to be focusing on the primary path.

I don't really have much more else to say on the issue, except to point out that Effective Java Second Edition now contains an item (59) warning against the danger of checked exceptions, and also contains an idiom for working around them by the use of a state-testing method (basically breaking the assertion and execution up in two steps).

[/quote]

 Reaches biside monitor and grabs book... the title is "Avoid unnecessary use of checked exceptions".  From it: "They force the programmer to deal with exceptional conditions." and "The burdon is justified if the exceptional condition cannot be prevented by proper use of the API and the programmer using the API can take some useful action once confronted with the exception".

Ask yoruself this: you give your program to your grandmother to run, she clickes on the .jar and it seemingly does nothing.  You find out that you screwed up and forgot to include some file, it was renamed, whatever, and your program simply crashed instead of poping up a dialog box letting her know that you goofed.  Which is the better experience for her?  Your program not doing anything OR feedback that it didn't work?

The API you gave, opening a file, makes sense, given rule 59, to be a checked exception.  Also, to me, the programmer can AND should do something reasonable in this situation.  Simply ignoring the error is a bad idea IMO.

Also, for the case you give, Class.getResourceAsStream seems to be the better API to use...

..darcy

phil swenson replied on Mon, 2008/08/18 - 6:00pm in response to: D'Arcy Smith

"If you make such a change then you would need to add 400 catches anyways, unless you like your programs crashing, but now you don't have the safetly of the compiler telling you that there were actually 401 places to chage it."

 

No no no... that's the point of exceptions, they "bubble up" to a layer where you handle it.  At the top thread handler in most cases.  So for a runtime exception you might be able to handle it in 1 place (if it's a web application for example 1 place would work nicely, and probably tell the user "sorry we couldn't execute your request, please try again later"and log/email the error).  So RuntimeException just needs handling at the external layer (UI layer usually) and that's it.  No need for 400 try/catches.  And it's not really 400 catches if you propogate the error, it could be many many more as you start putting in "throws ProcessNotFound Exceptions" all the way up the call chain you could easily run into 1000s of places to change your code.  Checked Exceptions don't scale.  This is why a lot of java code degrades to "throws Exception".  It just becomes too unwieldy to pass on all those throws clauses.

 I think this the our fundamental difference: you think you can and should handle exceptions as low down the stack as possible and I think they in general should bubble.  My position is that almost always they are unrecoverable problems and you should just report them to the user or process executer. 

 You didn't answer my sql question.  Let's say you have a user creating an account and you encounter a SQL Excepiton on the Account.create() method deep down in the stack.  How would the checked SQL Exception help you?  What would you do?  Write a try{ account.create()} catch(SQLException e){Log(e))} ??? or do a throws SQLException all the way up the chain?  How would you handle it?

phil swenson replied on Mon, 2008/08/18 - 6:12pm in response to: D'Arcy Smith

"Ask yoruself this: you give your program to your grandmother to run, she clickes on the .jar and it seemingly does nothing.  You find out that you screwed up and forgot to include some file, it was renamed, whatever, and your program simply crashed instead of poping up a dialog box letting her know that you goofed.  Which is the better experience for her?  Your program not doing anything OR feedback that it didn't work?"

 

Is anyone advocating hiding exceptions?  I haven't seen anyone say this.

D'Arcy Smith replied on Mon, 2008/08/18 - 7:17pm in response to: phil swenson

[quote=philswenson]

"If you make such a change then you would need to add 400 catches anyways, unless you like your programs crashing, but now you don't have the safetly of the compiler telling you that there were actually 401 places to chage it."

 

No no no... that's the point of exceptions, they "bubble up" to a layer where you handle it.  At the top thread handler in most cases." 

Think of a GUI - several places where you have threads.  But, sure, you deal with the exception where appropriate.

 

"So for a runtime exception you might be able to handle it in 1 place (if it's a web application for example 1 place would work nicely, and probably tell the user "sorry we couldn't execute your request, please try again later"and log/email the error).  So RuntimeException just needs handling at the external layer (UI layer usually) and that's it.  No need for 400 try/catches."

No needfor the with checked exceptions- you add "throws XXX" as appropriate if the method cannot handle the exception.

 

"And it's not really 400 catches if you propogate the error, it could be many many more as you start putting in "throws ProcessNotFound Exceptions" all the way up the call chain you could easily run into 1000s of places to change your code."

Again, you are not supposed to be modifying the signature of public methods, but I will happily accept that it happens (I know I do it in my code).  Adding "throws XXX" is not a huge issue.  I did this once with a project that threw Error everywhere and then all the exceptions where handled properly after the fact (not sane, don't suggest it).

 

"Checked Exceptions don't scale.  This is why a lot of java code degrades to "throws Exception".  It just becomes too unwieldy to pass on all those throws clauses."

I am sorry, but that is a terribe argument.  For years I have heard people complain about this, nobody has presented a reasonable argument yet that makes this seem like a burdon.

 

"I think this the our fundamental difference: you think you can and should handle exceptions as low down the stack as possible and I think they in general should bubble.  My position is that almost always they are unrecoverable problems and you should just report them to the user or process executer"

You are wrong in one assumption - I also advocate handling them up as high as it is practical.  Perhaps the difference is that I don't write web apps and I do write things that have multiple threads.

You (the crowd that you are talking about, maybe not you as an individual) seem to think that you should wrap your one entry point with try/catch(RuntimeException) but, in my experience, that leads to bug ridden code.  

It doesn't matter if the error is recoverable or not - it matters as to wether you should expect the error or not.  I never expect a NullPointerException or an ArrayIndexOutOfBounds in properly debugged code.  Those are programmer errors, not external issues.  

 

"You didn't answer my sql question.  Let's say you have a user creating an account and you encounter a SQL Excepiton on the Account.create() method deep down in the stack.  How would the checked SQL Exception help you?  What would you do?  Write a try{ account.create()} catch(SQLException e){Log(e))} ??? or do a throws SQLException all the way up the chain?  How would you handle it?"

I would do the same as I think you would do - put the try/catch at the entry point and bail on the program.  The difference is that I would know I would have to do it and not have it crash the program.

If you don't know what is thrown then you don't know what to catch.  If you catch RuntimeException you can mask programmer mistakes.

Someone earlier said that they catch NullPointerExceptions - the only sane way to do that is on a line by line basis where the line being wrapped in try/catch does not have a method call.  If they are catching NullPointerException and assuming what it is from inside of a block of code then they are potentially hiding bugs (I would go so far as to say tha tthey are hiding bugs).

..darcy

D'Arcy Smith replied on Mon, 2008/08/18 - 7:19pm in response to: phil swenson

[quote=philswenson]

"Ask yoruself this: you give your program to your grandmother to run, she clickes on the .jar and it seemingly does nothing.  You find out that you screwed up and forgot to include some file, it was renamed, whatever, and your program simply crashed instead of poping up a dialog box letting her know that you goofed.  Which is the better experience for her?  Your program not doing anything OR feedback that it didn't work?"

 

Is anyone advocating hiding exceptions?  I haven't seen anyone say this.

[/quote]

 

How do you know what exceptions to catch?  How do you guarnatee that you don't miss one?

..darcy

Casper Bang replied on Mon, 2008/08/18 - 8:22pm in response to: D'Arcy Smith

The beauty of exceptions is that they cascade, I've seen many a program that could make use of the following lines rather than trying (and failing) to handle the problem at call site. It happens a lot in NetBeans for instance, so often you don't realize "something is wrong" until a few minutes later when your attention is drawn to a small red icon in the status bar.


    try{
        MyApplication.start(...);
    }catch(Throwable e){
        if(JOptionPane.showMessageDialog(null, "Internal error! " +
                "Would you like to submit an error report?") == JOptionPane.YES_OPTION){
            DebugReport report = new DebugReport(Logger.getInstance());
            DebugMailer.submit("myapplication-issues@mycompany.com", report);
        };
        System.exit(-1);
    }

Mark Software replied on Tue, 2008/08/19 - 12:36pm

These exceptions seem to instigate some heated debate.

My personal gripe is the willy-nilly throwing and catching of RuntimeExceptions. If you dare to set a break-point on an ArrayIndexOutOfBoundsException (because you want to know exactly where it happens) in a debugger, any application with a good set of libraries is going to stop many times before even entering any useful code.

It's a disgrace. And a royal pain in the behind.

If I could dictate it I would disallow anyone to throw a RuntimeException with the intent to catch it just a little later. They're not called 'unchecked' for nothing.

Mark

 

Chris Beams replied on Tue, 2008/08/19 - 1:12pm

For those that are not familiar with it already, consider reading Effective Java Exceptions by Barry Ruzek.  Though he makes no mention of Spring particularly, the article captures quite well the perspective that Spring takes regarding checked vs. unchecked exceptions.

Contrary to popular belief, Spring is not 'anti-checked exceptions': rather, all exceptions coming from the Spring codebase represent (in Rusek's terms), 'fault conditions' such as programmer error or other unrecoverable catastrophic events (network down, database down, out of memory, etc).

The Spring codebase is 100% framework code, and this is why its exceptions are unchecked.  The only problems that can occur therein fall into this 'fault' category.

Contrast this, however, with application code.  Imagine you are authoring the object model for a financial domain.  In this domain are the usual suspects: Account, AccountRepository, and perhaps a TransferService.  On the transfer service we find a transfer(Account src, Account dest, MonetaryAmount amount) method.  What if the caller attempts to transfer an amount greater than the balance available in the source account?  Naturally, this represents a real-world contingency that is part of the business domain: an 'insufficient funds error'.  This kind of error maps perfectly onto checked exceptions.  The TransferService API should declare 'throws InsufficientFundsException'.

Why?  Because it is a contingency (again, see Rusek's article) from which our application can recover.  It is an issue that you as the designer of that API probably want callers to think about.  If this exception is thrown, the caller (perhaps the UI) should prompt the user to try again.  We don't want this exception just bubbling right up the stack -- it can be handled gracefully in a very direct fashion.

The bottom line is that the appropriate place for checked exceptions is when they are part of the application domain and represent a recoverable condition.  Conversely, framework or other infrastructural code should strongly consider throwing only unchecked exceptions, as the errors that occur from those APIs almost certainly represent fault conditions.

In cases where code that is beyond our control inappropriately throws checked exceptions (JDBC, for one example), we're left feeling the pain of catch-wrap-and-rethrow or other sub-optimal approaches.  This is one place that Spring itself can help.  For example, Spring's JdbcTemplate does this translation dirty work for you.  In other cases, sometimes APIs change when they realize that checked exceptions are inappropriate - Hibernate moved to an all-unchecked exception model in version 3.0.

It is important to distinguish between proper use of checked exceptions and the unfortunate misuse of them historically (even in the JDK as many have mentioned above).  We should be careful not to throw the baby out with the bathwater here; checked exceptions can be a wonderfully expressive mechanism when used judiciously.  Consider Rusek's concepts of fault vs. contingency to discern when to use each.

Best regards,

Chris Beams
Sr. Consultant, SpringSource
Lead, Spring Java Configuration
http://springsource.com
http://springframework.org/javaconfig

Kisito Momo replied on Wed, 2008/08/20 - 4:18am

look at this:  

 String myMethod(String value)
{
   if(currenState.equal(SomeBadState1))
   throw new MyException1()

what's the better way to advice a client code that during myMethod execution the state can be bad and then it must do some special thing (else the system can remain in the inconsistent state)? checked or unchecked exception?

William Houghtaling replied on Mon, 2011/07/04 - 6:15am

Check exceptions for me is really important to some components that we use and we could also say that there are some things that Check exeptions could do and couldn't do and that it could also be said with Runtime exceptions. Some components are needed to fully use this and it is not all the time that we could use them in every components. Gauthier, Houghtaling and Williams

Sandeep Bhandari replied on Mon, 2011/12/12 - 11:49am

Exceptions is one of the most important and always improving concept in Java. Even interviews also take exception handling as one of the main concept to discuss about. Checked exception has been dis-regarded more than being used primarily because of those mandatory catch blocks.

Carla Brian replied on Wed, 2012/06/13 - 12:08pm

This is a nice tip by the way. This could be helpful. I learn something new today. Thanks. - Joe Aldeguer

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.