Effective Java Exceptions

Home

News: Effective Java Exceptions

  1. Effective Java Exceptions (61 messages)

    Barry Ruzek has written "Effective Java Exceptions" for BEA's dev2dev, which points out that some say Java exceptions are an experiment that failed, and that the fault lies with Java library designers who failed to acknowledge the two basic causes of method failure. Addressing the exception handling code that tends to litter Java, he offers as an example the IOException:
    An I/O failure is a serious but extremely rare event. On top of that, there is usually nothing your code can do to recover from one. Java programmers found themselves forced to provide for IOException and similar unrecoverable events that could possibly occur in a simple Java library method call. Catching these exceptions added clutter to what should be simple code because there was very little that could be done in a catch block to help the situation. Not catching them was probably worse since the compiler required that you add them to the list of exceptions your method throws. This exposes implementation details that good object-oriented design would naturally want to hide. This no-win situation resulted in most of the notorious exception handling anti-patterns we are warned about today. It also spawned lots of advice on the right ways and the wrong ways to build workarounds.
    There are two classes of exceptions, he explains. One type of exception is a contingency, which means that a process was executed that cannot succeed because of a known problem (the example he uses is that of a checking account, where the account has insufficient funds, or a check has a stop payment issued.) These problems should be handled by way of a distinct mechanism, and the code should expect to manage them. The other type of exception is a fault, such as the IOException. A fault is typically not something that is or should be expected, and therefore handling faults should probably not be part of a normal process. [Editor's note: is the Blue Screen of Death therefore a fault or a contingency?] With these two classes of exception in mind, it's easy to see what should be checked and should be unchecked: the contingencies should be checked (and descend from Exception) and the faults should be unchecked (and descend from Error). Spring is notable for introducing a common translation from checked to unchecked exception types for faults, and some recent libraries apply that model innately. Lastly, Mr. Ruzek suggests the use of AOP for management of exceptions, because it really is a common and normal problem for Java programmers that isn't isolated to a specific domain, making it ideal for an aspect-oriented solution. Altogether an excellent read.

    Threaded Messages (61)

  2. strongly disagree with this[ Go to top ]

    I strongly disagree with this view. I've had to deal with obscurely failing code on production servers. Sloppy exception handling is one of the things that make life hard. Some code smells: - catching Exception, or worse Throwable - not logging an exception. If your code is so brilliant it will never fail, you'll definitely want to know if Murphy proves you wrong. - abusing the return type for returning error information (that's just retarded) - throwing run-time errors for things that are not fatal. If I see a run-time error in the log that means a programmer screwed up with handling errors or checking input somewhere or that something is seriously wrong with my system. Oh and IOExceptions are just about one of the most often occuring exceptions. Network connections are unreliable as hell and recovering can be as simple as trying again or failing gracefully. Assuming IOExceptions don't happen is not very smart. Besides, a modern IDE makes exception handling code so easy that there's not excuse for being lazy.
  3. I often use the IOException as the perfect example of a Java Exception hierachy. It easily allows consuming code to catch exceptions that they know about, care about and can handle, and meanwhile allow the library to add additional exceptions with out breaking the interface. Forcing code to either deal with an exception or bubble it up is a key point in writing stable, fault tolerant software. I can't stand it when I see code that says "Catch Exception or Catch Throwable." When I see that I know I am dealing with an unprofessional coder, or a set of code that is not meant to be deployed to production.
  4. Forests and trees[ Go to top ]

    I strongly disagree with this view. I've had to deal with obscurely failing code on production servers. Sloppy exception handling is one of the things that make life hard.

    Some code smells:
    - catching Exception, or worse Throwable
    - not logging an exception. If your code is so brilliant it will never fail, you'll definitely want to know if Murphy proves you wrong.
    - abusing the return type for returning error information (that's just retarded)
    - throwing run-time errors for things that are not fatal. If I see a run-time error in the log that means a programmer screwed up with handling errors or checking input somewhere or that something is seriously wrong with my system.

    Oh and IOExceptions are just about one of the most often occuring exceptions. Network connections are unreliable as hell and recovering can be as simple as trying again or failing gracefully. Assuming IOExceptions don't happen is not very smart.

    Besides, a modern IDE makes exception handling code so easy that there's not excuse for being lazy.
    I think your focusing too much on the example and too little on what the article is saying. If you expect your code to gracefully handle network failures and the ilk then, for you, those are contingencies, not faults. The big-picture reasoning still holds. It's just hard to implement in an API because you don't know whether your client considers a failure a fault or contingency, so you make it a contingency and let the caller wrap it as a fault.
  5. Re: Forests and trees[ Go to top ]

    If you expect your code to gracefully handle network failures and the ilk then, for you, those are contingencies, not faults. The big-picture reasoning still holds. It's just hard to implement in an API because you don't know whether your client considers a failure a fault or contingency, so you make it a contingency and let the caller wrap it as a fault.
    To add to what Erik says here, the same IOException could be a contingency in one context and a fault in another. For exampe, you throw the IOException back to a retry point. At this level it's a contigency. The code at the retry point executes it's predetermined number of retry attempts. On the last retry, it should probably re-throw the IOException as a fault. Also realize that throwing these as faults doesn't mean you don't handle them. The fault-block concept is key. Look at the diagram on page 2 if you have not. It's where you capture all unhandled exceptions and do something reasonable with them. It might be logging and contacting support. I might be throwing up a message to a user. It depends on the application. But this is nothing like just ignoring them. It's actually much more likely to succeed than trying to handle faults all over the place.
  6. I feel one of the reasons people tend to do a 'catch Exception' is because it is often the simplest way to have a contigency for any type of exception ,thought I do agree its not the most elegant way . I feel no language so far allows you to handle multiple exceptions in a single block.Some thing like .. try { ...code }catch(FileNotFoundException or EOFException fe){ --- handle it in a common way --- }catch(MyAppException ae){ ------- handle differently ---- } I feel it mandates a new JSR
  7. I feel one of the reasons people tend to do a 'catch Exception' is because it is often the simplest way to have a contigency for any type of exception ,thought I do agree its not the most elegant way . I feel no language so far allows you to handle multiple exceptions in a single block.Some thing like ..

    try {
    ...code
    }catch(FileNotFoundException or EOFException fe){
    --- handle it in a common way ---
    }catch(MyAppException ae){
    ------- handle differently ----
    }

    I feel it mandates a new JSR
    Unfortunatelly, you are completely wrong. The concept of Exceptions was introduced in the early operating systems in the 60s and languages like Ada, C++, etc, first of all, to centralize error handling and remove it away from the sources of errors. Unlike error codes, exceptions are meant to be handled in specially designed - and thoughtfully placed - catch blocks. There is nothing "not elegant" about catching a Throwble, because, in most cases, it is all you need to catch. Over 90% of all cases call for a catch block that must catch EVERYTHING (that means, a Throwable) and treat all caught errors generically - in the same way. These are your unrecoverable [system, application, or programming] errors. In rare cases, defined by business requirements - and ONLY by business requirements - more specific catch blocks are needed. That is the idea. And everything was fine until Java authors came up with "checked" exceptions that proved to be just glorified error codes that the compiler throws right in your face when you don't care about them and you have to deal with them immediately - one way or another, either by handling them or by adding them to the method's signature and creating a major ripple effect throughout your application. Note that if you have done your design work properly and implemented the above-mentioned strategic catch blocks (one catch-all, and only a few business-specific - even in a most elaborate app), every checked exception becomes nothing but an annoying pest that gets in your way - for no reason. You already know that all your errors will be caught and handled properly, and yet, the compiler bugs you with those stupid IOExceptions, or the likes of them. You now have to waste your time (and pollute your code) to wrap them into RT exceptions so that they reach your designated handler. At least, that's what most good programmers do these days. The rest just fall into the trap and start "handling" those checked exceptions as they pop up - just as if they'd deal with error codes in C. And that creates a chaos of unimaginable proportions. Many people have written articles on how to make exceptions work well in Java. The problem with most those methodologies is that they all take the existence of the checked exceptions for granted and try to find the right way to use them. There is no good way to use checked exceptions. Period. They are a mistake. They defy the purpose and the concept of Exceptions. Worst of all, they mislead developers into a false sense of security. Checked exceptions have the effect completely opposite to what the authors of Java had envisioned. Most developers now handle _only_ checked exceptions - and forget about the rest. Java is a great language, with at least one horrifying flaw - checked exceptions... Shame on Sun for not publically admitting this for 10 years...
  8. This is a really good article! Although I don't think IOException is a good example of a fault. In some situation it can be (e.g. if reading some internal resource file fails). But in other cases it is defenitely a contingency. E.g. if a user types in a file name or URL or something and and accessing that throws an IOException. Then the application can, and should, deal with it. But apart from that I agree with everything said.
  9. Excellent article![ Go to top ]

    I think this article is spot-on, but I think designing good exceptions is harder than the article lets on, and almost impossible due to the existing structures. Consider IOException. Let's say the code is openning a file and reading it. In the case that the user specified a file name, the file not existing will be a contigency, because good programs should always be prepared for bad inputs. But if the program is reading a config file that is part of it's standard installation, then it would be a fault, because the program can reasonably expect to the properly installed. So essentially the same exception can be a fault or a contingency depending on context. The result is when in doubt, make it a contingency (the principle evident in the standard library) or just make it a fault (common other places). But as we've seen, this doesn't really work. I think the problem is that whether or not an exception is a fault or a contingency is often orthogonal to its type. So I would say that instead of having one "throws" keyword and determining whether or not an exception is checked based on type, the compile should have two keywords for raising exceptions, one which raises a fault and one which raises a contingency.
  10. Re: Excellent article![ Go to top ]

    I think this article is spot-on, but I think designing good exceptions is harder than the article lets on, and almost impossible due to the existing structures.

    Consider IOException. Let's say the code is openning a file and reading it. In the case that the user specified a file name, the file not existing will be a contigency, because good programs should always be prepared for bad inputs. But if the program is reading a config file that is part of it's standard installation, then it would be a fault, because the program can reasonably expect to the properly installed.

    So essentially the same exception can be a fault or a contingency depending on context.
    This is where exception chaining really shines and my biggest complaint about this article was that it didn't focus enough on how it can be used to solve a lot of the problems described in this article. In short, I think you need to determine what exceptions should be declared on a method by method basis. And there's no reason you can't declare an unchecked exception. The best thing about this article is that it gives some good terminology to things I am already doing. For example I have a fault-barrier in a recent design. I didn't have a good name for what it was before.
  11. ... there's no reason you can't declare an unchecked exception.
    I'd prefer if Java *required* that unchecked exceptions that are thrown in the code block of a method and can escape the method be listed in the method signature. -Patrick -- Patrick Linskey http://bea.com
  12. ... there's no reason you can't declare an unchecked exception.


    I'd prefer if Java *required* that unchecked exceptions that are thrown in the code block of a method and can escape the method be listed in the method signature.

    -Patrick

    --
    Patrick Linskey
    http://bea.com
    Would that include those thrown by methods called in that method?
  13. Would that include those thrown by methods called in that method?
    No -- otherwise, we'd be back where we are with checked exceptions. Just exceptions that are both thrown by the method's code block and are not then caught within the same code block. Now, if we're really going to get into wish-list territory, I'd love to see some sort of packaging mechanism in Java, and a means to designate on an assembly basis that a given exception should be checked within the assembly but unchecked when it's thrown outside of the assembly. This would allow assembly authors to get the compiler benefits of checked exceptions for things that they cared about without having to burden the users of their code to necessarily be as rigorous about exceptions that they're unlikely to meaningfully handle. -Patrick -- Patrick Linskey http://bea.com
  14. This is the approach I'm following after struggling a lot. Fault or Contingency, in my experience, is something the the API cannot decide. The *context* of usage (the client) defines that. So, an API should not force the client to catch or throw and exception ever. Now, if you would like to show that your API can actually raise some exceptions that you consider alternative flows of your API's Use Cases, list them on the throws clause. So, in my actual architecture 1- Everything is Runtime 2- Those exceptions that I consider possible alternative use cases, I list them in the throws clause of my methods. 3- All those Exceptions that are really unexpected, remains unexpected, just like a NPE.
  15. Fault or Contingency, in my experience, is something the the API cannot decide. The *context* of usage (the client) defines that.
    Agreed.
    So, an API should not force the client to catch or throw and exception ever.
    How do you get to that conclusion? I would say that the API should always force the client to deal with the exception instead. Then they at least have to think about it and decide whether it's fault or contingency. I think the real reason is the syntax of exception handling, which is why I looked for an alternative (already mentioned here, Maybe from Haskell).
    Now, if you would like to show that your API can actually raise some exceptions that you consider alternative flows of your API's Use Cases, list them on the throws clause.
    Assuming anyone ever actually reads the javadocs or source, yes. IDE users don't. Plus, it's easy to get unchecked exceptions out of sync with what actually happens in the source, making listing unchecked exceptions in source basically useless.
  16. Now, if you would like to show that your API can actually raise some exceptions that you consider alternative flows of your API's Use Cases, list them on the throws clause.


    Assuming anyone ever actually reads the javadocs or source, yes. IDE users don't. Plus, it's easy to get unchecked exceptions out of sync with what actually happens in the source, making listing unchecked exceptions in source basically useless. +1 The purpose of checked exception is to infact cause the developer to make the decision about how each exception that can occur in use of the API should be handled. If the developer doesn't make this decision, they will never have a chance of creating a reliable application. IOException is a great example of an Exception that does reveal a lot of useful things that can, in fact be handled as contingencies. Then, if that code can not recover from one of them, it can rethrow the appropriate exception as a fault to allow the client application to then notify the "user" or system logging what has transpired. This is how exceptions should work and be used.
  17. I think bruce eckel (author Thinking in Java) got it right: http://www.mindview.net/Etc/Discussions/CheckedExceptions Throw runtime exceptions and let them bubble to the top (except for cases like validation exceptions). Catch checked exceptions and rethrow as runtime. The top thread should log the exception and decide whether to proceed. Seriously, what are you going to do with a SQL Exception? 99% of the time a SQL exception means your DB is down or you have a bug. There is no way to recover from this. Logging the exception and continuing with the app as if nothing is wrong just hides the problem. Letting the exceptions bubble to the top leads to bug discovery (error message presented to the user) or system problem discovery much more quickly. The code is easier to maintain as well, w/o the throws 10 exception crap. I also use exceptions for checking input params. I throw RuntimeExceptions if they are wrong.... this leads to fewer bugs making it to production, the invalid input cases are more likely to be caught in the testing phase. (Yeah, assertions also work for this) There is a reason no other language supports checked exceptions. In theory it sounds great, in reality it doesn't work well.
  18. There is a reason no other language supports checked exceptions. In theory it sounds great, in reality it doesn't work well.
    Maybe you should just read Barry Ruzek's article?
  19. Re: Excellent article![ Go to top ]

    "So I would say that instead of having one "throws" keyword and determining whether or not an exception is checked based on type, the compile should have two keywords for raising exceptions, one which raises a fault and one which raises a contingency." I agree, even though I've effectively stopped using exceptions in Java. However, I think the division between fault and contingency is artificial - every predictable fault is a contingency. Every unpredictable fault should be an Error, not an Exception (such as OutOfMemoryError). The checked exception syntax itself puts people, including me, off writing good code with exceptions. That's why I stopped using them, except where APIs demand it. There is a way of throwing a checked exception type without compiler checking - I think it's in the crazy undocumented Unsafe class. I'm not sure I'd advocate it, but it's there.
  20. Re: Excellent article![ Go to top ]

    "So I would say that instead of having one "throws" keyword and determining whether or not an exception is checked based on type, the compile should have two keywords for raising exceptions, one which raises a fault and one which raises a contingency."

    I agree, even though I've effectively stopped using exceptions in Java.
    What do you do instead?
  21. Re: Excellent article![ Go to top ]

    "So I would say that instead of having one "throws" keyword and determining whether or not an exception is checked based on type, the compile should have two keywords for raising exceptions, one which raises a fault and one which raises a contingency."

    I agree, even though I've effectively stopped using exceptions in Java.


    What do you do instead?
    int rc; rc = doSomething(); if (rc != SUCCESS) { switch (rc) { case ... case ... default ... } } rc = doSomethingElse(); if (rc != SUCCESS) { switch (rc) { case ... case ... default ... } } ugghhhh...that brings back memories I'd rather forget...
  22. Re: Excellent article![ Go to top ]

    ugghhhh...that brings back memories I'd rather forget...
    That's what I fear but I thought I'd see if there were some other option. I'm reminded of a discussion where one person stated that exceptions weren't needed because you should just open a dialog when the error occurs. Not that that is what is being suggested.
  23. Re: Excellent article![ Go to top ]

    ugghhhh...that brings back memories I'd rather forget...


    That's what I fear but I thought I'd see if there were some other option.

    I'm reminded of a discussion where one person stated that exceptions weren't needed because you should just open a dialog when the error occurs. Not that that is what is being suggested.
    I bet with closures (or I suppose function objects) and some sort of signaling/event raising mechanism you could architect something better than exceptions. You could, say, make it so that when an exception is raised it gets passed to some pre-registered error handler that either "fixes" the error so the code can continue, blows up the code and makes the stack unwind, or passes it along to the next handler. You might get some benefits from making the error handling chain independent from the stack...although I think you would still need one per thread. I'm pretty sure you could do this in Lisp or Smalltalk. Maybe it's possible in Java, but it would look clunky and unnatural. People smarter than me probably have some better ideas. I'm just trying to come up with an alternative. I'm not sure this would even work well. But it's certainly worth exploring.
  24. Once for all exception[ Go to top ]

    This is from a thread I created:
    I wrote an exception which looks like:

    class OnceForAllException extends RuntimeExcepion {
    public String code;
    public String category;
    public String message;
    public String[] parameters;
    }
    Since I wrote this exception, I never seem to need write another exception. (Sorry I did write another unchecked exception which is to do some longjmp signaling).

    This exception has a few key benefits:

    1. unchecked (runtime) exception: I am a believer in unchecked exception. I totally agree that checked exception does not scale and can't be used inside a framework.
    2. I18N support: you can map category to an I18N bundle, parameters are used to hold parameters that are independent of i18n strings.

    Of course when catching (handling) an exception, instead of using mutiple catch blocks, I have to use if/else/... inside a catch block. But I think this is an advantage because lots of times you want to do something common to some or all the exceptions you are trying to handle (catch). For example, suppose you have to rollback db transaction for some exceptions, instead of doing:

    ...
    } catch(FirstExcetion ex) {
    conn.rollback();
    throw ex;
    } catch(AnotherExcetion ex) {
    conn.rollback();
    throw ex;
    } catch(ThirdExcetion ex) {
    conn.rollback();
    throw ex;
    }
    ...
    I will do:

    ...
    } catch(OnceForAllExcetion ex) {
    if (ex.getCategory().equals("cat1") &&
    (ex.getCode().equals("code1") ||
    ex.getCode().equals("code2") ||
    ex.getCode().equals("code3")
    )) {
    conn.rollback();
    }
    throw ex;
    }
    ...
    Of course, if conn.rollback() is some complex operation, it is very hard to organize your code elegantly using just catch blocks.

    Someone might say you lose the benefit of type check. But if your exception hierarchy is runtime only, your IDE or compiler won't complain if the exception is missing anyway. Auto-code-completion can be accomplished by defining code and category as string constants.

    I bet you can't create an exception class for every error condition in your software but you sure should use code for each error condition no matter how weird the error might be. An exception message is never good for exception handling. Codes are much more scalable than exception classes. They are used in operating system calls, DBMS etc. They are more friendly to internationalization too.

    Now I have a few questions:

    1. Do you think one exception is enough (or almost enough)? Could you list your reasons no matter you agree or disagree?
    2. Do you write an exception class for every error condition? Does it scale? If not, do you use error/exception code? Do you have an alternative solution?

    I do miss the IDE type checking, autocompletion etc. Maybe this is a place for language innovation.

    Thanks.
  25. Re: Once for all exception[ Go to top ]

    2. Do you write an exception class for every error condition? Does it scale? If not, do you use error/exception code? Do you have an alternative solution?
    I would create a base exception for the given API, and extend it for specific cases where the caller might want to distinguish. Eg. FileNotFoundException is an IOException, right? You might include an error code into the base exception, if you like, but I think it is much more natural to use catch rather than a long select.
  26. Maybe I do this[ Go to top ]

    "What do you do instead?" I use the Maybe type, ported from Haskell. Most of the time it doesn't really matter why there's a failure, it matters that there's a failure. For those cases where the failure reason matters, there are other solutions, such as the Either type, ported from Haskell. I blogged about this a bit ago.
  27. Re: Effective Java Exceptions[ Go to top ]

    I think the article is better written than the summary suggests.
    This article argues that the fault does not lie with the Java model, but with Java library designers who failed to acknowledge the two basic causes of method failure.
    I would argue that exceptions are essential in Java, they are one of the features that makes the language great. Whether exceptions or another error reporting method is used, any API designers or API consumers must consider. 1) Is the problem with the inputs to the system or is the problem with the environment the system is running in. 2) Is the error reported properly so appropiate action can be taken. 3) Does the problem reporting mechanism (exception type) lock your API consumer into your API. (preferably NOT). Unfortunately, this has been a side effect of a lot of API's, e.g. code written to call EJB's which spends more time handling the EJB API than addressing points 1 and 2. Exceptions lke SOAPException can/will do the same unless the developer is careful. As Jilles said, theres no easy/lazy way to do this!
  28. Re: Effective Java Exceptions[ Go to top ]

    The terminology used in the article is helpful (fault, contingency, fault barrier), but I disagree with the conclusions. When writing code and using an external library, I need to know the ways in which that library can fail (either because I misused it, or a system failure, or bad internal coding etc). The only way the library has of informing me of what unexpected conditions I have to deal with is via checked exceptions. The alternative is for me to deploy code and then be confronted with a "NotOnATuesdayException" that isn't documented and that I haven't thought about. And that's dangerously sloppy. Yes, I know that having to deal with a checked exception or rethrow it is a pain to think about, but with an IDE it isn't *that* much of a pain, and is less of a pain than being woken up at 3am on Tuesday. Besides, chained exceptions can be used effectively in a well-thought strategy for dealing with faults. Sometimes I do think it is correct for me to "catch Throwable", particularly if it prevents a Thread dying in a server. I have also used it in a fault barrier to delineate that I have dealt with all errors occurring inside my code, and that the runtime system can continue (classic example is at the end of an event handler, where my implementation of a comms protocol is designed to detect and recover from gross errors). All in all, the Java checked exceptions aren't perfect, but they are much better than the alternatives.
  29. Re: Effective Java Exceptions[ Go to top ]

    The terminology used in the article is helpful (fault, contingency, fault barrier), but I disagree with the conclusions.

    When writing code and using an external library, I need to know the ways in which that library can fail (either because I misused it, or a system failure, or bad internal coding etc). The only way the library has of informing me of what unexpected conditions I have to deal with is via checked exceptions.

    The alternative is for me to deploy code and then be confronted with a "NotOnATuesdayException" that isn't documented and that I haven't thought about.
    But what are you going to do when you catch this NotOnATuesdayException? This is pretty bad example as a NotOnATuesdayException would be expected to occur a regularly (every Tuesday) and therefore, by this authors argument, declared as a CheckedException. If you are assuming that you have handled all the possible exceptions that could occur, you are in trouble. The only strategy for success is to assume that something you haven't considered may occur and handle it in your fault-barrier. No matter how many exceptions they declare, there can always be a bug in the code that throws a NullPointerException. You have to deal with that. There is a real danger in assuming that because there are no declared exceptions that no exception handling is required. If the exception can be handled, then the library author should declare it. They author of this article doesn't suggest otherwise. Actually that's exactly what he does suggest. And yes, authors of general libraries or methods that are going to be used in a wide array of situations need to be more explicit than someone writing a very specific piece of business logic.
  30. Re: Effective Java Exceptions[ Go to top ]

    Sometimes I do think it is correct for me to "catch Throwable", particularly if it prevents a Thread dying in a server.
    While this is true in most cases, there are types of Error (and Exception) that do require special handling, or should not be handled. For example, this will lock up some versions of the Sun JVM if a ThreadDeath is thrown: try { .. } catch (Throwable e) { throw new RuntimeException(e.toString()); } Here are some to treat with care: - ThreadDeath - simple clean-up only; don't new an exception - OutOfMemoryError - unless a very careful "transactional memory" coding stye is used universally (i.e. unless you are NASA), some data structure in the system will likely be in a screwed up state. - InterruptedException - do you know why you should or shouldn't call Thread.currentThread().interrupt() when this exception happens? There are others as well, but those three are the first to come to mind. Peace, Cameron Purdy Tangosol Coherence: Shared Memory for Java
  31. blue screen[ Go to top ]

    A fault is typically not something that is or should be expected, and therefore handling faults should probably not be part of a normal process. [Editor's note: is the Blue Screen of Death therefore a fault or a contingency?]
    Hopefully you are joking, but a blue screen is clearly a fault.
  32. I've complained about this multiple times in other threads. Lo and behold, a relevant topic to post it in. The scoping separation of the try {}, catch {}, and finally {} clauses is retarded. Especially finally. The lexical scope of variables defined in the try {} block should be accessible in the catch and finally, so we can avoid having to clutter code with extra variable defs outside the try..catch. Consider, as is common with many JNI libraries that require cleanup before deallocation: Connection c = null; Statement s = null; ResultSet rs = null; String connectionstring = config.get("connstring"); String querystring = args.get("Query"); try { c = getConnection(connectionstring); s = c.prepare(querystring); rs = s.execute(); //iterate } catch (ConnectException ce) { log("Connectionerror: "+ connectionstring); } finally { rs.close(); s.close(); c.close(); } I would like the first three statements to be eliminated: try { String connectionstring = config.get("connstring"); String querystring = args.get("Query"); Connection c = getConnection(connectionstring); Statement s = c.prepare(querystring); ResultSet rs = s.execute(); //iterate } catch (ParseException pe) { // catch can see the querystring var from the try block log("Parse Error: "+ querystring); } catch (ConnectException ce) { // catch can see the connectionstring var log("Connectionerror: "+ connectionstring); } finally { rs.close(); // finally can see the ResultSet rs object s.close(); // finally can see the Statement s object c.close(); // finally can see the Connection c object } In the second, we don't have the variable definitions outside of the relevant try catch block, the code looks much cleaner in my opinion. This problem especially rears its head when you're refactoring bad code that lacks exception detection, logging, and handling. Adding try..catch is trivial in my version, since you don't have to do extract variable definitions from the code block so they are visible to the catch and finally. I would also like an alternate syntax for doing statement-by-statement exception handling, such as: Connection c = getConnection("connection info") except:(TimeoutException te) { reconnect(); } except:(ConnectionsAllUsed cau) { changeserver(); } except:{ /*default*/ logandthrow();}; Statement s = c.prepare("a big query", querydate); except:(ParseException pe) { redirect("ErrPage"); } except:(DataException de) { error("bad data"); } ResultSet rs = s.execute(); except:(EmptySetException es) {redirect("EmptyPage"); } I hope that encapsulates the idea. This would improve readability rather than a long try..catch block since it sort of encapsulates the error handling at the source of the error detection.
  33. About exception declarations - your code is broken, because if closing the ResultSet throws an exception, then the Statement and Connection don't get closed. The only real way to safely open and close nested resources is with nesting. Using the closures syntax: withClosable(Connection connection: openConnection())     withClosable(Statement statement: connection.prepareStatement(etc))         withClosable(ResultSet resultSet: statement.executeQuery(etc))             stuff(resultSet); Without the closures syntax, it's still doable, but it's so damn long that I can't be bothered typing it here.
  34. About exception declarations - your code is broken, because if closing the ResultSet throws an exception, then the Statement and Connection don't get closed.
    Also, if an exception were thrown from the creation of the connection, statement or resultset, that code throws an NullPointerException from the finally block (bad news).
  35. About exception declarations - your code is broken, because if closing the ResultSet throws an exception, then the Statement and Connection don't get closed.

    The only real way to safely open and close nested resources is with nesting. Using the closures syntax:

    withClosable(Connection connection: openConnection())
    withClosable(Statement statement: connection.prepareStatement(etc))
    withClosable(ResultSet resultSet: statement.executeQuery(etc))
    stuff(resultSet);

    Without the closures syntax, it's still doable, but it's so damn long that I can't be bothered typing it here.
    A long time ago, I write a JDBC helper class that is used as follows. DatabaseManager mgr = SQLFactory.getConnection(...); try { String sql = "..."; ResultSet rs = mgr.executeQuery( sql ); while( rs.next() { } sql = "..."; mgr.executeUpdate( sql ); } finally { mgr.close(); } You never have to explicitly close anything. Under all situations it closes ResultSets, Statements and Connections for you, automatically. I've thought about putting this out on java.net lately, but I never really hear people griping about this issue as you have. My experience is in line with the comments here. JDBC's api is terrible for managing all the objects. But, the API that I put together really hides all of those issues, completely.
  36. A long time ago, I write a JDBC helper class that is used as follows... [code snipped] You never have to explicitly close anything. Under all situations it closes ResultSets, Statements and Connections for you, automatically.
    You have to close the manager explicitly, do you not? I am using a simple wrapper library that I wrote that is used like this: Query query = QueryManager.getQuery("select foo from bar"); query.execute(new RowHandler() { public boolean handle(Row row) { System.out.println("foo = " + row.getString("foo")); return true; } }); You don't have to close anything. Cleanup happens when after the last row is returned. I have also been able to add optimizations post-mortem. For example, I have it set up such that the PreparedStatement that backs the query will remain live as long as the client Query object is live (and the connection that it is associated is still valid.) I could also add local caching too without affecting the way the caller is used if I needed it. Anonymous functions, closures, and or function pointers would make this even better.
  37. A long time ago, I write a JDBC helper class that is used as follows.


    DatabaseManager mgr = SQLFactory.getConnection(...);
    try {
    String sql = "...";
    ResultSet rs = mgr.executeQuery( sql );
    while( rs.next() {
    }

    sql = "...";
    mgr.executeUpdate( sql );
    } finally {
    mgr.close();
    }


    You never have to explicitly close anything. Under all situations it closes ResultSets, Statements and Connections for you, automatically. I've thought about putting this out on java.net lately, but I never really hear people griping about this issue as you have. My experience is in line with the comments here. JDBC's api is terrible for managing all
    the objects. But, the API that I put together really hides all of those issues, completely.
    I have done this before, then found that not all JDBC drivers are the same. Some close all dependent objects when the connection closes and some don't, causing major headaches. I now handle everything explicitly (or would do if I was still doing explicit JDBC). Kit
  38. I have done this before, then found that not all JDBC drivers are the same. Some close all dependent objects when the connection closes and some don't, causing major headaches. I now handle everything explicitly (or would do if I was still doing explicit JDBC)
    For me, your reasons supports the above "pattern". You need to change only one piece of code to get it right. You might have delegates in the helper for the different drivers, but it would be interesting to the user of you API. As you said, apart from very special cases, there are much better ways to access a database than raw JDBC :-) Cheers, Tamas


  39. I have done this before, then found that not all JDBC drivers are the same. Some close all dependent objects when the connection closes and some don't, causing major headaches. I now handle everything explicitly (or would do if I was still doing explicit JDBC).

    Kit
    That's the point of my API. When you call mgr.release(), it does the following: if( resultSet != null ) resultSet.close(); if( preparedStmt != null ) preparedStmt.close(); if( stmt != null ) stmt.close(); if( conn != null ) releaseConnToPool( conn ); I've used this with Oracle, Sybase, MS ODBC bridge, MYSQL, Postgresql and probably some others that I'm forgetting. I decided to go ahead a put it out on java.net. It's under http://sqlfactory.dev.java.net.
  40. If you are using JDBC, consider using the Spring's JDBC support. Take a look at Spring's JdbcTemplate class. It basically does everything for you leaving you with having to write the SQL query itself, and, if necessary, the mapping method to map a single row from the ResultSet object to your custom object. That's it. For years - ever since my first excersise with JDBC, and the frustration caused by having to replicate the same ugly error-prone code over and over again - I have used a framework of my own that was based on exactly the same principle. The framework encapsulates everything reusable, including exception handling - ensuring that it's always done correctly, and only exposes the ResultSet object - through an abstract class that must be implemented by custom subclasses (and only if you are reading data from a ResultSet into custom objects.) Spring does it beautifully, packs lots of additional useful functinoality. Actually, when your application does not require elaborate DB schemas, and you have only the need for simple save/retrieve operations, I'd recommend using Spring's JdbcTemplate approach over Hibernate or other ORM technologies. It's just so simple, quick and elegant! Spring even provides support for smooth and painless LOB handling - that may, otherwise, be an issue if you are using Oracle.
  41. The only real way to safely open and close nested resources is with nesting. Using the closures syntax:

    withClosable(Connection connection: openConnection())
    withClosable(Statement statement: connection.prepareStatement(etc))
    withClosable(ResultSet resultSet: statement.executeQuery(etc))
    stuff(resultSet);

    Without the closures syntax, it's still doable, but it's so damn long that I can't be bothered typing it here.
    ... unless you factor it out into a reusable function. Then all you have to do is something like: try { // ... } finally { cleanup (connection, statement, resultSet); }
  42. While we are making up new finally/cleanup syntax, how about: Connection connection = openConnection() finally Util.close(connection); Statement stmt = connection.prepareStatement(etc) finally Util.close(stmt); ResultSet rs = stmt.executeQuery(etc) finally Util.close(rs); stuff(rs); The compiler would turn each finally into the usual declaration with "= null;", put the rest of the enclosing block into a nested try/catch/finally, and put the close into the finally block. Sort of "fire and forget" cleanup statements. When you'd open a file you'd go finally close(file); at the point of opening and be done with it. What's wrong with it: if you want to add a catch block too you'll need the full blown try/catch/finally. And if you do lengthy processing after "stuff(rs);" that doesn't need the connections, they will remain open unnecessarily long. But that may be bad design to begin with -- one method = do one thing.
  43. The compiler doesn't need to do this for you. Instead, you need to use the power of OO programming and Java to create the right control frame works for your application architecture. As I showed in my SQLFactory/DatabaseManager implementation above, you can create a fairly generalized mechanism with fairly concise and useful constructs. The extra information I didn't share then was that if you forget to call mgr.release(), a timer is running which will eventually close everything down for you. Also, the first argument is a "footprint" string that is used as a key to determine when unexpected concurrent access occurs. I.e. only one manager for one footprint can exist at any one time. This helps you manage how database access is performed. If you need "operation" level synchronization, you can use just a plain string like "mytablename". If you need key based synchronization you can use "mytablename"+keyvalue. If you are just doing massive input to the database and don't care about locking, you can add the use of an incrementing integer to say it doesn't matter. There is also an overall connection timeout that causes the connection to be recycled periodically to allow resources which may be leaking or otherwise accumulating related to the connection to be released.
  44. While we are making up new finally/cleanup syntax, part 2: Introduce stack objects that have destructors. Then the code will be: Connection connection; PreparedStatement stmt (connection, etc); ResultSet rs (stmt, etc); OMG, that's C++! Let's perform an exorcism!
  45. While we are making up new finally/cleanup syntax, part 2:
    Introduce stack objects that have destructors. Then the code will be:
    Connection connection;
    PreparedStatement stmt (connection, etc);
    ResultSet rs (stmt, etc);
    OMG, that's C++! Let's perform an exorcism!
    +1 very funny and yet so true
  46. You can't access those for a reason. It could lead to undefined state. try { String a = getA(); } catch (CannotCreateAException e) { // What should be the value of A here?! } Checking for error condition after each call is back to the 80s, it would mix error handling and normal flow together. Exceptions are, well, exceptions to the normal flow, they are a very powerful language element, you can handle the problems were you should/could, and keep normal execution paths clean. It is faster as well, since you don't need to check state after the call, because you can assume that it was successful. Your suggestion is basically the same as with try {} catch() now, but with an ambiguous syntax. It offers nothing more than eliminating the 'try' keyword and some brackets. Cheers, Tamas
  47. You can't access those for a reason. It could lead to undefined state.

    try {
    String a = getA();

    } catch (CannotCreateAException e) {
    // What should be the value of A here?!
    }

    Checking for error condition after each call is back to the 80s, it would mix error handling and normal flow together.
    Exceptions are, well, exceptions to the normal flow, they are a very powerful language element, you can handle the problems were you should/could, and keep normal execution paths clean.
    It is faster as well, since you don't need to check state after the call, because you can assume that it was successful.

    Your suggestion is basically the same as with try {} catch() now, but with an ambiguous syntax. It offers nothing more than eliminating the 'try' keyword and some brackets.


    Cheers,

    Tamas
    In the case of the ambiguous reference, my point is that the block-local variable "a" should maintain its lexical scope across what would normally in java would be different scopes. Essentially, the try, catch, and finally blocks all are treated as a single block. The closing "}" of the try block, which in normal java scoping rules would end the scope of "a" in the SPECIAL case of try...catch...finally would not. While this would break the "purity" of {} blocks, who cares. try catch is a special block anyway, since it is encompassed by keywords try catch and/or finally. Your bias against per-statement error checking is only due to the fact in the 80s you HAD to do per-statement checking of error codes or they disappear. You are correct that you could mock up a close approx, but the "try" keyword in front of real statements would significantly adversely impact the readibility of the code. My wish is to have the OPTION of per-statement compact error handling. There are many cases where it would be useful, and the code readability improved. So while you may consider the elimination of try as "nothing more", I would consider it a small but quite substantive improvement. I guess we wouldn't need a special character and all the debate that entails. I would be happy with: Map data = service.invoke() catch (NotAvailable na) redirect("serverdown.html"); catch (ValidationError ve) refresh(data);
  48. You can't access those for a reason. It could lead to undefined state.

    try {
    String a = getA();

    } catch (CannotCreateAException e) {
    // What should be the value of A here?!
    }



    In the case of the ambiguous reference, my point is that the block-local variable "a" should maintain its lexical scope across what would normally in java would be different scopes. Essentially, the try, catch, and finally blocks all are treated as a single block.

    The closing "}" of the try block, which in normal java scoping rules would end the scope of "a" in the SPECIAL case of try...catch...finally would not.

    While this would break the "purity" of {} blocks, who cares. try catch is a special block anyway, since it is encompassed by keywords try catch and/or finally.
    I think you don't get my point. In methods, local variables must be explicitly initialised. In case of the above example, if 'A' won't get initialised due to an exception, the value of A would be undefined in the catch part. I'm not against the extending the scope of the variables there, but it is technically not feasable. Let's look at another example: try { String a = generateA(); String b = generateB(); } catch ( InvalidArgumentException iae ) { } In the above example if generateA() throws an exception B won't be even created, but with "extended" visiblility scope, you could access it, yet again the value is undefined.
    There are many cases where it would be useful, and the code readability improved. So while you may consider the elimination of try as "nothing more", I would consider it a small but quite substantive improvement. I guess we wouldn't need a special character and all the debate that entails. I would be happy with:

    Map data = service.invoke()
    catch (NotAvailable na) redirect("serverdown.html");
    catch (ValidationError ve) refresh(data);
    As far as I can see, in your syntax the 'excepts' would be in the same scope as the previuos line, with all the problems mentioned above. It is a matter of taste. I'm not overwhelmed by such syntactic changes. They may save some lines of code, but I think they make the language more ambiuous / complex. (2c) Cheers, Tamas
  49. how about an always block[ Go to top ]

    One item I'd add to Java is an 'always' block (like a try block). The difference being that an always block would go to its catch section then return to where at failed and continue. This would be really helpful for clean up scenarions. Imagine finally { always { stream1.close(); stream2.close(); stream3.close(); } catch (IOException e) { log.warn("Exception closing stream", e); } } instead of the current finally { try { stream1.close(); } catch (IOException e) { log.warn("Exception closing stream1", e); } try { stream2.close(); } catch (IOException e) { log.warn("Exception closing stream2", e); } try { stream3.close(); } catch (IOException e) { log.warn("Exception closing stream3", e); } }
  50. Re: how about an always block[ Go to top ]

    instead of the current

    finally {
    try {
    stream1.close();
    }
    catch (IOException e) {
    log.warn("Exception closing stream1", e);
    }

    try {
    stream2.close();
    }
    catch (IOException e) {
    log.warn("Exception closing stream2", e);
    }

    try {
    stream3.close();
    }
    catch (IOException e) {
    log.warn("Exception closing stream3", e);
    }
    }
    This is totally wrong. You need nested try/finally blocks to clean up multiple resources!
  51. Re: how about an always block[ Go to top ]

    AOP can be used for resources cleanup. Suppose an aspect which will collect references to all created disposable resources (streams, connections, etc) in a TLS and will clean them upon method exit. I've implemented such thing and it works fine for over a year now, however implementation is incomplete because AOP framework we're using can't intercept local variables access. Here's more full description from our internal docs.
  52. fault or contingency[ Go to top ]

    OK.... OK... It is my FAULT to think that we don't need a CONTINGENCY plan; clearly we now need a CONTINGENCY plan for the FAULTs we expect. :-) Confused? Read Declared Unchecked Exception: The Best of Both Worlds
  53. Re: fault or contingency[ Go to top ]

    Confused? Read Declared Unchecked Exception: The Best of Both Worlds
    rather the Worst of Both Worlds!
  54. Re: Effective Java Exceptions[ Go to top ]

    Although the article adresses the seperation between RuntimeExceptions and checked ones, I think this article ( http://www.javasvet.net/resource/68/AboutEffectiveExceptionHandling.pdf ) adresses the issue better by providing a more detailed categorization. The "fault barrier" is a special case of a good design strategy for dealing with Exceptions over several layers. One of the things I try to keep in mind is that for many layers (and utility related classes) it's better to declare checked exceptions and not log the error, because you do not know the severity nor the probability of the exception occuring in that layer.
  55. I think you're all just confused :)[ Go to top ]

    The book "Effective Java" covers this topic pretty well, so I recommend you read it. My own opinion is that people want to do away with checked exceptions because they are not aware of any hard-and-fast rules for when to use one or the other. If this was clearer I think most people would agree it makes sense. My own interpretation is as follows: - If the user violates any API preconditions, the method should throw a RuntimeException. - If the user meets the API preconditions and some recoverable exception occurs nonetheless, the method should throw a checked exception. - If the user meets the API preconditions and some unrecoverable exception occurs nonetheless, the method should throw an error. I think that IOException is a very difficult beast to categorize. Consider FileNotFoundException for example... The user can check whether the file exists, then he goes to open it and gets a FileNotFoundException because it is possible that in between the two calls someone removed the file. A checked exception or error makes sense in that case, but Errors are never meant to be caught so I would argue a checked exception makes more sense (so you can log the exception or bring up a GUI dialog, etc). You are absolutely right that *most* users don't get IOException *most* of the time. It is also true that most of the time you end up logging IOException instead of really recovering from it. Still, I don't consider IOException to be a RuntimeException because it isn't an example of a programmer error and should not be silently ignored. The user violated no preconditions so he should check and handle this kind of exception. Wrapping it up with a RuntimeException and rethrowing might make sense most of the time, but it's a choice the user should make depending on what makes sense for his application. I definitely do not think it makes sense to *always* do it. Just my 2 cents. Gili
  56. Exceptions versus Compiler Warnings[ Go to top ]

    Often I get the feeling that the justification for checked exceptions is the same as the justification for paying attention to compiler warnings. Depending on the project you may want to ignore or be completely anal about it. If you're writing aircraft control systems you want to enforce your own code and all library code you use to explicitly deal with all possible error scenarios. That includes managing programmer bugs at runtime. Other times you want the code to be as readable as possible, with no extra clutter for error checking. Catching all errors and logging them at a fault barrier is splendid. Modern IDEs let you pick which potential programming problems to highlight in your code. Unchecked exceptions could be one of them.
  57. If you're writing aircraft control systems you want to enforce your own code and all library code you use to explicitly deal with all possible error scenarios. That includes managing programmer bugs at runtime. Other times you want the code to be as readable as possible, with no extra clutter for error checking. Catching all errors and logging them at a fault barrier is splendid.
    I think this is a false dichotomy and one that is too commonly believed by developers. It assumes that you must either catch all exceptions or let all exceptions fall through. Neither of these strategies, in my experience, is effective. You should be catching those exceptions that you should deal with (sometimes by re-throwing as a different type of exception) and letting those that need to be dealt somewhere else fall through. Unchecked exceptions are good for those things that really can't be dealt with except as a failure and checked exceptions are good for most everything else.
  58. That was not what I meant. My point was that which exceptions you want to deal with depends on your project as much as anything else. The same way you pick and choose what compiler warnings you pay attention to you also want to pick and choose which exceptions you handle explicitly. As others have stated before me: The code throwing the exception can (often) not determine whether it is a fault or a contingency. It usually depends on the context.
  59. Ruzek vs. Spring[ Go to top ]

    Barry Ruzek writes:
    Don't forget that the primary purpose of a fault exception is to convey diagnostic information that will be recorded to help people figure out what went wrong. Using multiple fault exception types is probably overkill, since your architecture will treat them all identically. A good, descriptive message embedded inside a single fault exception type will do the job in most cases. It's easy to defend using Java's generic RuntimeException to represent your fault conditions.
    So Spring's diversified JDBC RuntimeExceptions are 'overkill'?
  60. Another good help to choose what exception type (checked/unchecked) is appropriate, is to use the "Design by contract" (DBC) pattern. It defines "preconditions" the user of a method must adhere to fulfill the "contract". Example: @pre("i != null") public void myMethod(Integer i) { : } If the user violates the contract (calling the method with a null value) the result is considered "unpredictable" - If an exception is thrown - it should be always unchecked because it's considered a programming fault. Good DBC-Tools: Contract4J or Springcontracts
  61. Re: Effective Java Exceptions[ Go to top ]

    People who defend checked exceptions claim that they should represent recoverable errors. Fine. Except for one thing: whether the particular error in a particular application is recoverable or not is defined by the business requirements of that application! The same type of error may require an alternative action in one application, while treated as a generic fault by another. Expecting the compiler to tell you what to do with an error is wrong – and, well, incompetent! Not to mention: over 90% of all errors in most applications are (or should be) treated as non-recoverable. Gosling’s unbelievable suggestion that checked exceptions were designed to create a “creepy” feeling that something may go wrong is mind-boggling! Every junior software engineer should understand that “something” might ALWAYS go wrong in a piece of software! Checked exceptions are creating just the opposite effect: developers now feel completely “safe” and do NOTHING if the compiler does not remind them of an exception! Handling a checked exception is never enough because any such exception generally represents only a subset of all possible errors. People have forgotten – and many never have learnt – that error handling must be designed for, that it is an essential part of the application’s architecture and design. Instead, it has become an afterthought for most Java developers. People often ask: "Without checked exceptions, how do I know which error to expect/handle?" This question reflects the most common misconception about error handling. You do not need to know anything other than what is stated in the business requirements for your application. Everything else should be treated as "something bad that really wasn't meant to happen per design." This makes the general error handling strategy very simple! (Yes, there has to be a STRATEGY.) Here are the simple tasks that the developer/application designer must face when designing the high-level layout for the application: 1. Determine the location for the top-level handler that will catch all errors that bubble up to it from within the application/module. This is usually a "try/catch (Throwable t)/finally" construct around the process that implements the main task of your application or component/module. Call it a “fault barrier”, or whatever you want… 2. Get familiar with the business requirements (funny that I should mention that! :)) and single out the legitimate use cases where an error should be caught and handled before it reaches the above-mentioned top-level handler. Such handling will mean implementing an alternative action in response to the error. Such cases will represent your business errors. Note that since these errors are documented in your own business requirements, shame on you if you need the compiler to remind you about them! ;) It doesn’t matter if your business analyst did not supply you with well-stated requirements. You should have a set of well-defined design concepts (provided by someone else or gathered by yourself before you start coding.) You must design for all those alternative actions. In most cases, you won’t even need to distinguish between the types of errors occurred, just catch all possible exceptions in that API and redirect your process accordingly. In rare cases, yes, you might have to investigate the API a bit deeper to look for a more specific exception type. For example, you may want to distinguish the Spring's DataRetrievalFailureException from a NullPointerException. The former indicates that your data was not retrieved from the database; the latter indicates something totally unacceptable that has nothing to do with the business case. But such details are easy to uncover - if you look for them when following nothing but your business requirements. What developers must remember is that they absolutely must design for error handling. Instead, most Java programmers today thoughtlessly catch just about anything that the compiler points at, put wrappers around wrappers, re-throw useless exceptions but chop-off valuable stack traces, log the same error dozens of times at each step in the call stack, etc. Fortunately, in practice, most applications have very few cases of the distinct legitimate "business" cases mentioned in step 2. 3. Ensure that each error propagates freely from the source of the error to the only dedicated handler that is designed to handle it, the handler that has the sufficient application context to handle the error properly. Under no circumstances, the error should be caught and tinkered with before it reaches that handler. 4. When some (3rd party/JDK) code throws a checked exception, catch it in your API, and since, most likely, you don’t want to handle it immediately at the source of the error, wrap it inside your custom RT exception and re-throw so it can freely propagate to the dedicated (by design) handler w/o polluting the rest of your code on its way. 5. When re-throwing exceptions, always nest the cause exception within the new exceptions. Never discard the original error. 6. Always log the exception – with the full stack trace - when the dedicated handler ultimately catches it. And log it once. Run-time exceptions were designed to ensure all of that. Most importantly, they were designed to allow developers not to deal with errors at their immediate source but rather at the central point where the application was designed to handle them, while providing the developer with the complete stack trace information between the error source and the handler. The fact that the original JDK implementations – all the way up to 1.4 - provided no nesting functionality in the Exception class while forcing developers to deal with exceptions at the very source if each error - demonstrates how ill-conceived the whole idea was in its core from the beginning. Mixing checked and unchecked exceptions, as most people suggest, is a bad idea. As I have said, handling the specific checked exception in response to the compiler's complaint is never enough. If you stop there, you are guaranteed to miss something that will blow up your application. Therefore, you still have to do everything described above in 1 - 6, except your code is now polluted with tons of specific (most certainly, unnecessary) handlers that may interrupt an essential exception on its way to the one and only correct handler, which inevitably results in the loss of error information. If we can't reliably mix RT and checked exceptions, and we don't like RT exceptions, can we indeed make all exceptions checked? The answer is, most certainly, NO. There is a reason why the authors of Java didn't do that in the first place. They just couldn't. That would have made the language totally unusable. Every method would have to declare countless exceptions in its signature, and every method would have to deal with the countless checked exceptions thrown by the code inside. What for? Just to create that “creepy” feeling Gosling is so proud about? Finally, look at Sun's EJB3!!! Wow! No checked exceptions there! A silent admission of the mistake? But how many "average" programmers have noticed? There’s nothing wrong with making mistakes, and no one has ever claimed that Java was perfect. Many things have been improved and corrected in the language since its first release. It is time for Sun to come out and start helping the industry to recover from this terrible experiment that has resulted in nothing less than millions of programmers who are clueless about error-handling! That, in turn, costs companies hundreds of millions of wasted dollars. Sadly, no matter how many of the brightest people in the industry have spoken against checked exceptions (Rod Johnson, Bruce Eckel, Anders Hejlsberg, to name a few), it has had almost no impact on the programming “masses.” This forum just proves that.
  62. Re: Effective Java Exceptions[ Go to top ]

    .....
    Finally, look at Sun's EJB3!!! Wow! No checked exceptions there! A silent admission of the mistake? But how many "average" programmers have noticed? There’s nothing wrong with making mistakes, and no one has ever claimed that Java was perfect. Many things have been improved and corrected in the language since its first release. It is time for Sun to come out and start helping the industry to recover from this terrible experiment that has resulted in nothing less than millions of programmers who are clueless about error-handling! That, in turn, costs companies hundreds of millions of wasted dollars. Sadly, no matter how many of the brightest people in the industry have spoken against checked exceptions (Rod Johnson, Bruce Eckel, Anders Hejlsberg, to name a few), it has had almost no impact on the programming “masses.” This forum just proves that.
    +1
    And excellent methodology on how to design and deal with exceptions.