C# Question



  • I just need a little confirmation on this:

    So it is best practise to avoid the usage of try and catch blocks? Its best to avoid exceptions at all isn't it?

    Why?



  • It's not best practice to avoid exceptions, in C# or any language, it's best practice to let exceptions filter up, and only catch them when you absolutely must.

    Microsoft states this in their best practice suggestions mostly because in Java the opposite is usually recommended -- mostly due to throws statements. In Java, you often see things like

    try { file.write("Hello, world!");} catch(IOException e){}  // WTFery at its best. Equivalent to OnError Resume Next

    Why? Because write() throws an IOException, and you cannot compile unless you catch it. You could state that your method throws an IOException too, which would be the right thing to do, but for the most part folks don't do that, they just catch and ignore.

    The best practice for exceptions is to only catch them when you need to do something should an exception occur.



  • @Whiskey Tango Foxtrot? Over. said:

    It's not best practice to avoid exceptions, in C# or any language, it's best practice to let exceptions filter up, and only catch them when you absolutely must.

    Microsoft states this in their best practice suggestions mostly because in Java the opposite is usually recommended -- mostly due to throws statements. In Java, you often see things like

    try { file.write("Hello, world!");} catch(IOException e){}  // WTFery at its best. Equivalent to OnError Resume Next

    Why? Because write() throws an IOException, and you cannot compile unless you catch it. You could state that your method throws an IOException too, which would be the right thing to do, but for the most part folks don't do that, they just catch and ignore.

    The best practice for exceptions is to only catch them when you need to do something should an exception occur.

    Java's strict rules for exception handling are well-meant, but eventuelly leads to bad design, as you stated. "You could state that your method throws an IOException too" - well, but this method is called from other methods, so they must now handle the exception; or maybe this method overwrites a superclass method (or is required for the implementation of an interface) that doesn't throw the exception, so have to change that one too... and every method that uses this superclass/interface... it's not surprising that "catch(IOException e){} is chosen as the "solution".



  • @ammoQ said:

    Java's strict rules for exception handling are well-meant, but eventuelly leads to bad design, as you stated. "You could state that your method throws an IOException too" - well, but this method is called from other methods, so they must now handle the exception; or maybe this method overwrites a superclass method (or is required for the implementation of an interface) that doesn't throw the exception, so have to change that one too... and every method that uses this superclass/interface... it's not surprising that "catch(IOException e){} is chosen as the "solution".

    The whole point of declaring one's own method so it propagates the exception is to make the calling methods catch it. The whole point is that the low-level or mid-level method usually is not qualified or prepared to catch it and deal with it (and we all seem to agree that an empty catch block, or a catch block containing only a logging statement, does not qualify as "handling" it). Make the higher-level class (often a UI class) handle it!

    And if you're overriding a method and you want to change the exceptions it throws, you have no business overriding the method in the first place. The checked exceptions are part of the method's contract. They are meant to represent issues which the caller needs to be aware of; they are abnormal outcomes which the caller needs to be prepared to handle. If a subclass introduces new issues, then the contract of the superclass's method is violated.

    Checked exceptions lead to bad design because most programmers continue to insist on thinking in terms of C (or Pascal or Fortran) code, and they see exceptions as something that's just in the way.



  • There is also a perception of poor performance involved with using exceptions, from two diffrent sources (at least):  

    1) Earlier on in C++'s lifetime, they were pretty poor performing, but I think that's been largely resolved now...I've heard lots of folks just repeat the 'conventional wisdom' that exceptions are slow because they heard it 10 years ago :)

    2) In C# -- when running in debug mode -- there can be a significant delay between when the exception is thrown and when it gets handled...which gives the impression of pretty poor performance.  However, when you compile and run under release configuration, that doesn't seem to be a problem.

    -cw



  • @VGR said:

    And if you're overriding a method and you want to change the
    exceptions it throws, you have no business overriding the method
    in the first place. The checked exceptions are part of the method's
    contract. They are meant to represent issues which the caller needs
    to be aware of; they are abnormal outcomes which the caller needs to
    be prepared to handle. If a subclass introduces new issues, then the
    contract of the superclass's method is violated.

    It's not as if I wanted to override the exception it throws; the classes I'm using might want to throw some exceptions. While it is to some extend understandable that subclasses should not throw exceptions that the superclass didn't throw, it becomes a real dilema when implementing interfaces. Of course there is an easy "workaround", as seen in JDBC: about every single method of every single class is allowed to throw a SQLException. I wonder if there is a market for a "breaks everywhere" JDBC driver that really throws exceptions wherever possible, so you can finally test all the exception handling code for java.sql.Statement.clearWarnings().

    Unfortunetaly, the more exceptions you allow in one interface (though they are never thrown in real implementations), the more exceptions must be taken care of in the users of the interface, leading to even more checked exceptions. It's a bit like an arms race, until you reach the point of

    catch(Exception couldNotCareLess) {} 



  • @VGR said:

    Checked exceptions lead to bad design because most programmers continue to
    insist on thinking in terms of C (or Pascal or Fortran) code,
    and they see exceptions as something that's just in the way.

    I know that's the Microsoft party line, but it's nonsense. You might as well say "type checking leads to bad design because programmers think in terms of C code, so they just add type conversions everywhere instead of using the correct type". It's even a true statement to some extent (we've seen plenty of WTFs where people kept converting back and forth between string and integer values). But it's not a reason to abandon type checking, because it's only true for idiot programmers.

    Idiot programmers are what leads to bad design. Consider the cases:

    Idiot programmer, checked exceptions: bogus exception-discarding code.

    Idiot programmer, unchecked exceptions: untrapped exceptions that crash the program at runtime, because they didn't know to trap the exception.

    Competent programmer, unchecked exceptions: untrapped exceptions that crash the program at runtime, because they forgot that this function can occasionally throw an exception.

    Competent programmer,  checked exceptions: no untrapped exceptions at runtime, so the program doesn't crash (although in Java, not all exception classes are checked, so a few can still slip through - still better than not checking any of them).

    Lack of exception checking is not an advantage. It just moves the bug so that it's less visible. Compile-time static checks are a good thing; people who don't understand how to deal with them cannot be helped (fire them already!). Java has problems, but this is not one of them.



  • @asuffield said:

    Competent programmer, unchecked exceptions: untrapped exceptions that crash the program at runtime, because they forgot that this function can occasionally throw an exception.

    Competent programmer,  checked exceptions: no untrapped exceptions at runtime, so the program doesn't crash (although in Java, not all exception classes are checked, so a few can still slip through - still better than not checking any of them).

    Lack of exception checking is not an advantage. It just moves the bug so that it's less visible. Compile-time static checks are a *good* thing; people who don't understand how to deal with them cannot be helped (fire them already!). Java has problems, but this is not one of them.

    As you can see in JDBC and similar examples, the proliferation of checked exceptions quickly leads to the points where the programmer - competent or not - has to write exception handler code that never ever gets called till the end of the universe. And since you cannot declare new checked exceptions in subclasses or implementations of interfaces, there can be cases where there is nothing usefull you can do to handle the exception at that level. Well, typically is "solved" by delegating it to logging - as if a few lines in a log file would really take care of the problem. In many respects, catch(Exception e){} and catch(Exception e){logger.log(e);} are equivalent.
    The general question is always: If something really unexpected happens, would I rather want my program to crash or to ignore it silently? In many cases it's much better to crash than to continue in an uncertain state.


     



  • @ammoQ said:

    And since you cannot declare new checked exceptions in subclasses or implementations of interfaces, there can be cases where there is nothing usefull you can do to handle the exception at that level.

    public doSomething() throws DeclaredException {
    try {
    // do something
    } catch(UndeclaredException e) {
    throw (DeclaredException)new DeclaredException().initCause(e);
    }
    }

    It's lame but it's a way out



  • @JvdL said:

    @ammoQ said:

    And since you cannot declare new checked exceptions in subclasses or implementations of interfaces, there can be cases where there is nothing usefull you can do to handle the exception at that level.

    public doSomething() throws DeclaredException {
    try {
    // do something
    } catch(UndeclaredException e) {
    throw (DeclaredException)new DeclaredException().initCause(e);
    }
    }

    It's lame but it's a way out

    I think it's pretty normal. For example, a JDBC driver (sorry for constantly bringing JDBC examples;-) can throw SQLExceptions everywhere, but nothing else.
    So what will it throw when a network problem prevents it from reaching the database at all? Obviously, wrapping exceptions into other exceptions makes it for the calling method more difficult, if not impossible, to find out what really went wrong.

    Theoretically, you could always wrap your Exceptions into java.lang.Error objects and throw them, but this would be just a complicated way not to have checked exceptions.



  • So what will it throw when a network problem prevents it from reaching the database at all? Obviously, wrapping exceptions into other exceptions makes it for the calling method more difficult, if not impossible, to find out what really went wrong.

    Not when using initCause/getCause.
    The wrong way would be:  catch(UndeclaredException e) { throw new DeclaredException(e.getMessage()); }  // prior to Java 1.4

    Agree with ammoQ that declaring exceptions is a WTF design error by Sun. Not all's bad in Redmond.

    As to the OP: exceptions are good, catching is bad.

    As the name suggests, exceptions should occur only in exceptional circumstances beyond the program's control like when dealing with databases. That means the program can't handle it not before nor after and the best thing is to bubble it up to the highest level, where you, report to the UI, to the logs, email the admin, file a law suit etc.

    In cases within the program's control where you could catch and properly handle exceptions after the fact you most often can prevent the exception beforehand.

    During development and testing you'll stumble on NullPointers (NullRefs in C#) and other silly exceptions. Everyone makes mistakes. Let it throw, let it throw (E. Clapton). It would be disastrous if those errors go unnoticed by unnecessary catching.

    Exceptions to the rule apply: it would be silly to check whether a string represents a valid number before sending it to a parseDouble() method. The parser method will do a better job, catching and handling is cleaner than pre-checking it. In Java (but not in C#) you may want to catch exceptions that an interface declares that you are sure the implementation won't throw - but I woudn't recommend it: you'll never know when the implemetations will change.

    So my advice is:

    - when in doubt, throw an exception.

    - never catch exceptions unless you really know what you're doing

    - always use try{}finally{}  (or  using{} in C#) to clean up your mess
     


     



  • @JvdL said:

    As the name suggests, exceptions should occur only in exceptional circumstances beyond the program's control like when dealing with databases. That means the program can't handle it not before nor after and the best thing is to bubble it up to the highest level, where you, report to the UI, to the logs, email the admin, file a law suit etc.

    In cases within the program's control where you could catch and properly handle exceptions after the fact you most often can prevent the exception beforehand.

    Well, in some cases the program is more readable if the main part simply does what it is to do when everything goes fine, while all the dirty error handling is done below.

    An artificial example to show what I mean:

     

    Version 1: 

    ------------------ 

    try { 
      int  a=someSource.getNextInt();
      int b=theOtherSource.getNextInt();
      int c = a/b;
      someDestionation.sendInt(c);
    }
    catch (SomeNotAvailableException e1) { ... }
    catch (IOException e2) {...}
    ...

    ------------------

     

    Version 2: 

    ------------------

      int  a; int b; int c;

      if (!someSource.isAvailable()) {
        ... /* handle error condition /
        return;
      )

      a=someSource.getNextInt();

      if (!theOtherSource.isOpen()) {
        ... /
    handle error condition /

        return;

      ) 

      b=theOtherSource.getNextInt();

      if (b==0) {
        ... /
    handle division by zero /
       return;
     }

     c=a/b;

    if (!someDestionation.isReady()) {
        ... /
    handle error condition */

        return;

      )

      someDestination.sendInt(c);
    ------------------

    As you can see,  all the error handling clutters the code in version 2, so it's hard to see what the thingy is actually supposed to do.





  • @ammoQ said:

    @JvdL said:

    As the name suggests, exceptions should occur only in exceptional circumstances beyond the program's control like when dealing with databases. That means the program can't handle it not before nor after and the best thing is to bubble it up to the highest level, where you, report to the UI, to the logs, email the admin, file a law suit etc.

    In cases within the program's control where you could catch and properly handle exceptions after the fact you most often can prevent the exception beforehand.

    Well, in some cases the program is more readable if the main part simply does what it is to do when everything goes fine, while all the dirty error handling is done below.

    An artificial example to show what I mean:

     

    Version 1: 

    ------------------ 

    try { 
      int  a=someSource.getNextInt();
      int b=theOtherSource.getNextInt();
      int c = a/b;
      someDestionation.sendInt(c);
    }
    catch (SomeNotAvailableException e1) { ... }
    catch (IOException e2) {...}
    ...

    ------------------

     

    Version 2: 

    (...ugly code...)


    ------------------

    As you can see,  all the error handling clutters the code in version 2, so it's hard to see what the thingy is actually supposed to do.

    I agree that version 1 looks much nicer then version 2, but this falls clearly under the first category: exceptions beyond the programs control. What are you going to do in those catch blocks? Send a random integer to some destination? What I tried to convey is that you should nothing with such exceptions: neither pre-emptive checks nor catch "handling". I would write the code as follows

     

    Version 3: 

    ------------------

     int  a=someSource.getNextInt();
     int b=theOtherSource.getNextInt();
     int c = a/b;
     someDestionation.sendInt(c);

    ------------------

    Period.

    My second category is those exceptions where you do have control, in which case I prefer pre-emptive checks over catching (in general).

    For example, if you there are alternative sources available you have control. In such cases prefer this:
     ------------------

    if( beanBagGirl.isAvailable() )

       beanBagGirl.getDate();

    else if( foosballGirl.isAvailable() )

       foosballGirl.getDate();

    else

       return "Brillant";

     ------------------

     rather than this:

     

     ------------------

    try {

       beanBagGirl.getDate();

    } catch( SmackInTheFaceException e1 ) {

       try {

          foosballLady.getDate();

       } catch( KickInTheGroinException e2 ) {

          return "Brillant";

      }

    }

     ------------------

    It's easier on the resources, too.

     


     



  • @JvdL said:

    I agree that version 1 looks much nicer then version 2, but this falls clearly under the first category: exceptions beyond the programs control. What are you going to do in those catch blocks?

    Mmmh, probably some logging or stuff... I see your point.

    Well, in some cases I could decide, based on the exception that happened, whether or not it's worth to try again later. 


    What I tried to convey is that you should nothing with such exceptions: neither pre-emptive checks nor catch "handling". I would write the code as follows

     

    Version 3: 

    ------------------

     int  a=someSource.getNextInt();
     int b=theOtherSource.getNextInt();
     int c = a/b;
     someDestionation.sendInt(c);

    ------------------

    Period.

    But Java doesn't let you, because your method is part of the implementation of some interface that is not allowed to throw checked exceptions. 

     

    My second category is those exceptions where you do have control, in which case I prefer pre-emptive checks over catching (in general).

    For example, if you there are alternative sources available you have control. In such cases prefer this:
     ------------------

    if( beanBagGirl.isAvailable() )

       beanBagGirl.getDate();

    else if( foosballGirl.isAvailable() )

       foosballGirl.getDate();

    else

       return "Brillant";

     ------------------

     rather than this:

     

     ------------------

    try {

       beanBagGirl.getDate();

    } catch( SmackInTheFaceException e1 ) {

       try {

          foosballLady.getDate();

       } catch( KickInTheGroinException e2 ) {

          return "Brillant";

      }

    }

     ------------------

    It's easier on the resources, too.

    I like your example :-)) 

    Those small try-catch-blocks are definitely more evil than the pre-emptive checks.



  • @JvdL said:

    Agree with ammoQ that declaring exceptions is a WTF design error by Sun. Not all's bad in Redmond.

    Checked exceptions are the Java equivalent of "lint" for C programs.

    After a while, it became evident in the C world that 98% of prorgrammers would do 'f = fopen(name, "r");' without checking whether f is NULL. Since the next line of code invariably deferenced f, crashes were abundant. The 'lint' program was conceived to put a stop to this. The fact is, whenever you open a file, you have no guarantee it will be present (and readable), so you MUST be prepared for the possibility that it won't be there.

    You can close your eyes real tight and stick your head in the sand and say "That probably won't ever happen," but that is the difference between an amateur programmer and a true professional: The amateur makes programs that sometimes work; the professional makes robust programs that either always work or let you know exactly why they didn't work.

    Microsoft hasn't done anyone a favor by telling them they don't have to bother to check whether a file opened successfully. They've just invited people to make crash-prone programs just like C programs with no lint-checking. And programs that bail out by showing IO.FileNotFoundException (or whatever the actual C# exception is) to the user are likely to end up on this site. A stack trace is as meaningful to a non-technical user as a Dr. Watson window full of hexadecimal register values.



  • @Ice^^Heat said:

    I just need a little confirmation on this:

    So it is best practise to avoid the usage of try and catch blocks? Its best to avoid exceptions at all isn't it?

    Why?

    Exceptions happen when something exceptional happens.. you created a file for writing but the user deleted it in the middle, the database server is down, some code needed a security assertion and it wasn't supplied, etc. So, you can't really avoid exceptions. As a rule of thumb, when your program flow is dependant on exceptions, then you need to rethink your design. Ideally, you're going to handle things like UI data validation before it gets back to your data source so you're not going to rely on exceptions for that.

    It's good form to catch the expected exception at the point you are prepared to handle it and never, ever, give a raw exception back to a user. Also, catch and act on the specific errors you're expecting first and then fall back to catching Exception, but only if you're prepared to handle it in that section of code.

    Be careful when you try, catch, throw

    Consider the following:

    try { //some file write process } catch(Exception e) { throw e; }

    versus:

    try { //some file write process } catch(Exception e) { throw; }

    The first example truncates your call stack, which will make your debugging hell.

    Now, as to your question on avoiding try catch blocks... that depends on the context. One of the reasons to use a try catch block is if you're going to clean up resources after an exception occurs. However, if the class supports IDisposable, then a using statement works as well and really reads nicely.

    DbConnection conn = new DbConnection(); 

    try {//some DB stuff } catch { } finally { //close db connection }

    versus:

    using(DbConnection conn = new DbConnection()
    {
      //some db stuff
    }

     



  • @VGR said:

    @JvdL said:
    Agree with ammoQ that declaring exceptions is a WTF design error by Sun. Not all's bad in Redmond.

    Checked exceptions are the Java equivalent of "lint" for C programs.

    After a while, it became evident in the C world that 98% of prorgrammers would do 'f = fopen(name, "r");' without checking whether f is NULL. Since the next line of code invariably deferenced f, crashes were abundant. The 'lint' program was conceived to put a stop to this. The fact is, whenever you open a file, you have no guarantee it will be present (and readable), so you MUST be prepared for the possibility that it won't be there.

    You can close your eyes real tight and stick your head in the sand and say "That probably won't ever happen," but that is the difference between an amateur programmer and a true professional: The amateur makes programs that sometimes work; the professional makes robust programs that either always work or let you know exactly why they didn't work.

    Microsoft hasn't done anyone a favor by telling them they don't have to bother to check whether a file opened successfully. They've just invited people to make crash-prone programs just like C programs with no lint-checking. And programs that bail out by showing IO.FileNotFoundException (or whatever the actual C# exception is) to the user are likely to end up on this site. A stack trace is as meaningful to a non-technical user as a Dr. Watson window full of hexadecimal register values.

    For the record: I have never claimed there's anything wrong with exceptions, only that the Java's mandatory declaration of exceptions in the method API has proved to be counterproductive. Just about every language that is less than 20 years old supports exceptions. To my knowledge, Java is the only one that insists on mandatory declarations.

    Your example of fopen does not convince me. The equivalent of fopen in C# throws an exception just like in Java. MS never told anybody to ignore unsuccessful file operations. Also I disagree that exceptions are a substitution for lint: the former is a compile time check, the latter a runtime check. I'll advise anyone to lint their Java and C# code just as they would C and C++, but that's OT.

    Here's a few arguments against mandatory declarations of exceptions.

    - It's inconsistent. Every method invocation can, and by Murpy's law, will at some time throw a Throwable. Why insist on declaring some and not others?

    - It's not OO. Declaration of exceptions reveals information about the implementation of a method, which it should not.

    - Time and time I have come across WTF code that eats exceptions. Reason? To improve the implementation of a utility method, aprogrammer uses a new JDK or external framework method that declares an exception. Or maybe some info previously gotten from a file is now taken from a DB or a web service. Therefore, the utility method must change its declaration, in fact it becomes a new method signature. Because of that, you must refactor all the code that uses the method. Worse, because exception declarations bubble up, you end up having to refactor your entire codebase. Not good. To get around this, many programmers have is taken the easy way out: Eat the exception. But that is even worse. The only proper way out is throw a runtime exception with an initCause. And that's exacttly the way C# works: every exception is a RuntimeException.

    - Avoid exceptions. In many peer reviews I've come across code that goes a long way avoiding exceptions by reinventing square wheels, hardcoding constants that are better placed in a config file and what not. The reason? People feel bad declaring exceptions as if that was a sign there was something wrong with their code.  It's stupid, but it's reality.

    The most convincing proof of the wrongness of it all is in the Sun's JavaDoc. Java used to have a useful utility called URLEncoder. There was a problem with that. So they "fixed" it. Read it here: http://java.sun.com/j2se/1.4.2/docs/api/java/net/URLEncoder.html . Think two seconds about the W3C recommendation that's quoted there and you realize "WTF? Who allowed hardware vendors to write software code?" If you're making web applications (and what else would you do with Java) you'll want to use URLEncoder everywhere. Not anymore: the new signature declares an UnsupportedEncodingException. Either you need to refactor your whole system, or you have to resort to square wheel regular expressions. Thank you, Mr. McNeally.

    So what would you do with exceptions? Bubble them up and catch them on the highest level. You know everything you need to know about the exception thanks to the stacktrace. But you'll know a lot more: the "intent of use". For example, in a web app, you should catch in the servlet's doGet/Post. Here you know what the user or external agent wanted: you know the URL, the params, the session state. Even if the only thing you can think of is bury it in a log file, you'll be able log a lot more information that will help you to reproduce and fix the problem. With a little effort, you can provide the user or agent with helpful information that allows him/her/it to go on with their business.

    What would happen if a SQL database system would adopt the practice of eating errors, burying them in log files, or return ramdom results, or think for you "well this doesn't work so you probably meant that"? Would you trust such a database as the backend of your Java application? I wouldn't. I want a database to tell me what's wrong, when something is wrong. And when I'm on the front end, I want Java middleware to do the same. Now that can be done with Java, but the mandatory declaration of exceptions makes it harder.

    PS. I'm not a MS fanboy. I prefer Java because it's open, but I welcome the competition from C#. Without it, we would never have have enjoyed the improvements of Java 5 and 6.



  • @JvdL said:

    For the record: I have never claimed there's anything wrong with exceptions, only that the Java's mandatory declaration of exceptions in the method API has proved to be counterproductive. Just about every language that is less than 20 years old supports exceptions. To my knowledge, Java is the only one that insists on mandatory declarations.

     

    You're getting closer to the real problem here. Let me return to the type checking analogy (actually, under the hood, exception checking is just a special kind of type checking anyway, so the technology involved is all identical).

    Imagine that you have a large, complicated data type. A strictly typed language in the style of C++ or Java might force you to dump that complex type into all your temporary variable declarations. You would likely object that this is ugly and messy.

    But the solution is not to discard the type-checking system.

    The problem with Java's exception checking system is not that Java has an exception checking system (as C# fanboys often claim). C#'s lack of one is not a solution to the problem, it's just a different kind of problem. The problem with Java's system is that it's awkward to use.

    There's no damn reason why it should be. We've had better type systems than this since long before Java came along - the Java designers just didn't bother to tackle the problem. What we should have instead is a type inference system for exceptions. Type inference is a problem that was solved decades ago - there's no actual reason why you should have to declare all your types (languages like Haskell give you strict type checking without having to specify any type declarations on your variables, ever). Basically, if you slap a type declaration on something, then that declaration must match. If you don't, then the type inference engine figures out the actual requirements and fills them in for you. In this case that would mean: if you don't specify a 'throws' declaration, the compiler creates one for you, consisting of everything you throw, plus everything that's throwable by all the functions you call. This is actually quite trivial to implement, and it's a mystery to me why Java still lacks it.

    Then you could just slap a declaration on your top-level functions saying that they can't throw anything (or can only throw certain exceptions), and the exception checker tells you what you forgot to catch. Library functions can require that you pass them callbacks which don't throw exceptions, etcetera. All the benefits without the bother of having to declare what each function does by hand.

    That's only one possible solution, but it gives you an idea of the real problem here. You don't want to remove checked exceptions, you want the implementation of them to be smarter.

    (There are plenty of problems with Java - just not the ones listed in Microsoft's PR material)
     



  • @asuffield said:

    Basically, if you slap a type declaration on something, then that declaration must match. If you don't, then the type inference engine figures out the actual requirements and fills them in for you. In this case that would mean: if you don't specify a 'throws' declaration, the compiler creates one for you, consisting of everything you throw, plus everything that's throwable by all the functions you call. This is actually quite trivial to implement, and it's a mystery to me why Java still lacks it.

    Then you could just slap a declaration on your top-level functions saying that they can't throw anything (or can only throw certain exceptions), and the exception checker tells you what you forgot to catch. Library functions can require that you pass them callbacks which don't throw exceptions, etcetera. All the benefits without the bother of having to declare what each function does by hand.

    It still doesn't work well with interfaces. Either interfaces restrict, as some kind of contract, the kind of exceptions an implementation may throw; or any method using an interface may be confronted with unexpected exceptions. Let me try to show my point by an simple example:

    There is an interface Comparable, used for SortedSet, SortedMap etc. Let's assume we want to manage instances of a class in a TreeSet, but the compareTo method is unsafe - e.g. because the class is an implementation of the "remote proxy" design pattern and needs to access a remote machine to do the comparison; so it could throw an IOException.

    Without Java's restrictions, we could write code like this:

    ...

    try {
       set.add(o);
    }
    catch (IOException e) {
      ... handle network error if we can, or just let the program die nasty ;-)
    }

     

    Unfortunately, Java doesn't allow us to throw an IOException in compareTo, even though we are willing to handle it indirectly (by letting it bubble up through the TreeSet object).

    Though this example might seem a bit over-simplified, issues like this emerge relatively quickly in larger systems that try to use standard libs.

     

     



  • @ammoQ said:

    It still doesn't work well with interfaces. 

    You're basically describing another of the real, major problems with Java - the type system is just too simplistic (you've almost certainly run into it before in various forms). Interfaces aren't expressive enough to talk about this problem and give you a sensible answer. We do have type systems that can handle this (such as the ones in Haskell and the ML family), but the C++/Java/C# family can't do it.

    Explaining how to build a type system that can handle this is the subject of many postgraduate courses - and frankly, it's out of my depth, I've used the things but I don't really understand why they work. In essence, you need to be able to talk about the polymorphic set of types that implement the interface Comparable but may or may not throw exceptions, and let the type checker figure out what the right restrictions to use in each particular case are.

    It is a source of continuing irritation to me that there are no mainstream languages that implement generic polymorphic typing. The kind of special-case polymorphism provided by the C++ family is useless when you have a problem like this one.



  • @asuffield said:

    The problem with Java's exception checking system is not that Java has an exception checking system (as C# fanboys often claim). C#'s lack of one is not a solution to the problem, it's just a different kind of problem. The problem with Java's system is that it's awkward to use.

    I basically agree with you. The problem is not checked exceptions themselves, which were intended to reduce bugs, but that Java's implementation of them leads to empty catchall blocks. Microsoft/C# chose to ignore the issue and recommended that you should simply document all possible exceptions.

    IMO, it's the more elegant solution. Invariably, if you start down the checked exception path, you end up making a decision that limits options.



  • @JvdL said:

    Here's a few arguments against mandatory declarations of exceptions.

    - It's inconsistent. Every method invocation can, and by Murpy's law, will at some time throw a Throwable. Why insist on declaring some and not others?

    What you're really asking is, what is the difference between checked exceptions and unchecked exceptions in Java?

    The answer is: checked exceptions are conditions over which the programmer has no control. Unchecked exceptions are caused by mistakes in one's code.

    Some unchecked exceptions don't even require a method call, like IndexOutOfBoundsException and NullPointerException. They exist to reveal errors in code. On the other hand, a SocketException is not caused by a coding mistake. No amount of safeguard code can prevent the conditions that lead to it.

    @JvdL said:

    - It's not OO. Declaration of exceptions reveals information about the implementation of a method, which it should not.

    You are supposed to wrap low-level exceptions in higher-level exceptions, to prevent callers from being exposed to the implementation. This is so important that exception chaining was added as a basic JVM feature in Java 1.4.

    Checked exceptions actually promote OO, by allowing methods which guarantee to fulfill their contract if they return without throwing an exception. Checked exceptions are very clear means of indicating some or all of the conditions under which the method won't return.

    @JvdL said:

    - Time and time I have come across WTF code that eats exceptions. Reason? To improve the implementation of a utility method, aprogrammer uses a new JDK or external framework method that declares an exception. Or maybe some info previously gotten from a file is now taken from a DB or a web service. Therefore, the utility method must change its declaration, in fact it becomes a new method signature. Because of that, you must refactor all the code that uses the method. Worse, because exception declarations bubble up, you end up having to refactor your entire codebase. Not good. To get around this, many programmers have is taken the easy way out: Eat the exception. But that is even worse. The only proper way out is throw a runtime exception with an initCause. And that's exacttly the way C# works: every exception is a RuntimeException.

    That's just bad programming. From the start, the method should have been declared to throw an exception which completely abstracts out the issue. For instance, the method should have been declared with "throws FrameworkException" (or something) and when the implementation changed, the only thing that a caller would notice, if they looked at all, was that the thrown FrameworkException wrapped a different type of lower-level exception.

    I agree that eating exceptions is almost always a WTF. But getting rid of them entirely is­—sorry for the overused cliché—throwing the baby out with the bathwater.

    @JvdL said:

    - Avoid exceptions. In many peer reviews I've come across code that goes a long way avoiding exceptions by reinventing square wheels, hardcoding constants that are better placed in a config file and what not. The reason? People feel bad declaring exceptions as if that was a sign there was something wrong with their code.  It's stupid, but it's reality.

    Then those people need to get over it and learn it's part of programming Java. And it's your job to point that out in a code review. Exceptions are not something to be worked around.

    I can sympathize with you. I've more than once encountered people who claim they need to catch every little exception (usually with an empty catch or a catch block containing only a logging statement) or it might "crash the system." Is it maddening? Yes. Will I give up trying to explain it? Hell no.

    @JvdL said:

    The most convincing proof of the wrongness of it all is in the Sun's JavaDoc. Java used to have a useful utility called URLEncoder. There was a problem with that. So they "fixed" it. Read it here: http://java.sun.com/j2se/1.4.2/docs/api/java/net/URLEncoder.html . Think two seconds about the W3C recommendation that's quoted there and you realize "WTF? Who allowed hardware vendors to write software code?" If you're making web applications (and what else would you do with Java) you'll want to use URLEncoder everywhere. Not anymore: the new signature declares an UnsupportedEncodingException. Either you need to refactor your whole system, or you have to resort to square wheel regular expressions. Thank you, Mr. McNeally.

    Did you actually look at the deprecation message, or the W3C paragraph? There is a good reason for the change. Assuming a particular text encoding, especially in a server environment, is a bad thing. You need to pass in the encoding explicitly. And anytime you pass in a character encoding, you need to be prepared for the possibility that it won't exist, especially since the exact set available may depend on support of the host environment.

    Web pages are almost universally generated from servlets. And if you're inside a servlet, you shouldn't catch or declare anything, because the servlet's "service" method (and things that use it, like HttpServlet.doGet) throws IOException already, of which UnsupportedEncodingException is a descendant.

    @JvdL said:

    So what would you do with exceptions? Bubble them up and catch them on the highest level. You know everything you need to know about the exception thanks to the stacktrace. But you'll know a lot more: the "intent of use". For example, in a web app, you should catch in the servlet's doGet/Post. Here you know what the user or external agent wanted: you know the URL, the params, the session state. Even if the only thing you can think of is bury it in a log file, you'll be able log a lot more information that will help you to reproduce and fix the problem. With a little effort, you can provide the user or agent with helpful information that allows him/her/it to go on with their business.

    On this we agree.

    @JvdL said:

    What would happen if a SQL database system would adopt the practice of eating errors, burying them in log files, or return ramdom results, or think for you "well this doesn't work so you probably meant that"? Would you trust such a database as the backend of your Java application? I wouldn't. I want a database to tell me what's wrong, when something is wrong. And when I'm on the front end, I want Java middleware to do the same. Now that can be done with Java, but the mandatory declaration of exceptions makes it harder.

    On this we also agree. I consider empty or log-only catch blocks the single worst thing a Java programmer can do. Sweeping errors under the rug only makes a class unreliable. They need to be caught at the highest level possible.

    @JvdL said:

    PS. I'm not a MS fanboy. I prefer Java because it's open, but I welcome the competition from C#. Without it, we would never have have enjoyed the improvements of Java 5 and 6.

    Debatable. I know for a fact that generics were in the Java 1.4 compiler, but were disabled. Microsoft wasn't really needed in order to realize that casting the contents of Collections was hard to read and hard to maintain. According to jcp.org, JSR 14 (Generics) was first officially drafted in 1999.



  • @VGR said:

    That's just bad programming. From the start, the method should have been declared to throw an exception which completely abstracts out the issue. For instance, the method should have been declared with "throws FrameworkException" (or something) and when the implementation changed, the only thing that a caller would notice, if they looked at all, was that the thrown FrameworkException wrapped a different type of lower-level exception.

    The "FrameworkExceptions" add little in helping the calling method to handle the exception. I call a method of the FooBar framework, it throws a FooBarException - that doesn't make me any wiser. Such "competely abstract" exceptions don't tell me anything how to solve the problem. But if I cannot do anything to solve the problem, why and how should I handle the exception at all? Eventually, the options left are "eat the exception (burry it in the log file)" or "let it bubble up, one way or another, and let the program die nasty"



  • @ammoQ said:

    @VGR said:

    That's just bad programming. From the start, the method should have been declared to throw an exception which completely abstracts out the issue. For instance, the method should have been declared with "throws FrameworkException" (or something) and when the implementation changed, the only thing that a caller would notice, if they looked at all, was that the thrown FrameworkException wrapped a different type of lower-level exception.

    The "FrameworkExceptions" add little in helping the calling method to handle the exception. I call a method of the FooBar framework, it throws a FooBarException - that doesn't make me any wiser. Such "competely abstract" exceptions don't tell me anything how to solve the problem. But if I cannot do anything to solve the problem, why and how should I handle the exception at all? Eventually, the options left are "eat the exception (burry it in the log file)" or "let it bubble up, one way or another, and let the program die nasty"

    Then make multiple exception abstractions. ResourceUnavailableException, ObjectAlreadyExistsException, OperationInterruptedException, and so on. If there's a lot of them, give them a common superclass, so a caller has the option of dealing with them all in a single catch block (while avoiding the cardinal sin of 'catch (Exception e)') or in more fine-grained catch blocks.



  • This is turning into a flame war, and is getting a little off topic. Let's settle down, shall we?

    I think we can all agree on the following:

    • Java's implementation of contractual exceptions is slightly flawed or at the very least requires some form of workaround.
    • C# chose to ignore the issue and place the burden of exception knowledge in the hands of the documenter.
    • Contractual exceptions *can* be a good idea, if properly implemented.
    • Microsoft couldn't figure out how to properly implement them, so rather than use a flawed implementation, they dropped it entirely.
    • Neither Java nor C# is particularly superior in terms of general capabilities. Which has the better library is debatable, but fodder for another thread. :)
    • Both the C# and the Java exception framework can lead to sloppy programming. In the case of Java, lazy programmers "eat" exceptions and/or neglect proper documentation of exceptions. In the case of C#, lazy programmers neglect proper documentation of exceptions.

    Ice^^Heat, I believe your question has been answered, and both sides in this mini-war agree. You should handle only the exceptions that you need to handle in order to properly control the flow of your program, and let the rest "bubble up", either by refusing to catch them (in C#) or by wrapping them (in Java). Sometimes you need to handle an exception. Sometimes you don't. Which depends on your program.

    If you are having trouble deciding which, please post your specific situation so that we can better help you determine whether you should catch or release your exception.



  • @Whiskey Tango Foxtrot? Over. said:

    This is turning into a flame war, and is getting a little off topic. Let's settle down, shall we?

    I think we can all agree on the following:

    • Java's implementation of contractual exceptions is slightly flawed or at the very least requires some form of workaround.
    • C# chose to ignore the issue and place the burden of exception knowledge in the hands of the documenter.
    • Contractual exceptions *can* be a good idea, if properly implemented.
    • Microsoft couldn't figure out how to properly implement them, so rather than use a flawed implementation, they dropped it entirely.
    • Neither Java nor C# is particularly superior in terms of general capabilities. Which has the better library is debatable, but fodder for another thread. :)
    • Both the C# and the Java exception framework can lead to sloppy programming. In the case of Java, lazy programmers "eat" exceptions and/or neglect proper documentation of exceptions. In the case of C#, lazy programmers neglect proper documentation of exceptions.

    Ice^^Heat, I believe your question has been answered, and both sides in this mini-war agree. You should handle only the exceptions that you need to handle in order to properly control the flow of your program, and let the rest "bubble up", either by refusing to catch them (in C#) or by wrapping them (in Java). Sometimes you need to handle an exception. Sometimes you don't. Which depends on your program.

    If you are having trouble deciding which, please post your specific situation so that we can better help you determine whether you should catch or release your exception.

    Well, I haven't read all the posts yet, there are many more replies than I hoped. So I guess I'll have to spent an afternoon processing all this information ;)



  • Well, If you would like to treat the checked exception as a runtime one, just do this:

     

    catch(CheckedException ce) { throw new RuntimeException(ce); } 


Log in to reply