7

I can't seem to phrase this correctly for the search engine to pick up any meaningful results.

try{
    BufferedReader reader = new BufferedReader( new FileReader("foo.bar") );
}
catch(Exception e){
    println( e.getMessage() );
}

So FileReader only throws the FileNotFoundException, which as I understand it is an IOException, which is an Exception. Can someone explain why I would catch FileNotFoundException or IOException instead of just specifying the generic "Exception" and not having to import an exception (i.e. import java.io.FileNotFoundException;)? Is it strictly for readability?

I've caught the exception using all three names and I can't find a difference.

EDIT:--------------------

private BufferedReader askUserForFile(String prompt){
        BufferedReader rd = null;
        while(rd == null){
            try{
                String filename = readLine(prompt);
                rd = new BufferedReader( new FileReader(filename) );
            }
            catch(Exception e){
                println(e.getMessage());
            }
        }
        return rd;
    }
patterned
  • 424
  • 3
  • 9
  • Because you'll catch heck from a lot of people if you catch Exception. (Exception included *a lot* of possible error conditions that you should not ignore, and if you catch Exception then you're setting yourself up for some nasty bugs.) – Hot Licks Dec 17 '13 at 21:06

6 Answers6

8

Exception is the mother of all exceptions, including all RuntimeException subclasses. When you specify to catch it, you'll get much more fish in the net than you wanted, like NullPointerExceptions, IllegalArgumentExceptions and so on.

While catching the generic Exception is the right thing to do at some point in your code, catching it at any lower layer is almost certainly wrong and can hurt the behavior of your application.

The more important skill to learn in Java is not how to catch exceptions, but how to not catch them, instead letting them propagate up the call stack, towards the exception barrier, the one common spot in the code where all errors are caught and uniformly handled (typically by logging, rolling back the transaction, and similar).

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • So I've edited my post. For the method askUserForFile, is this being done correctly? Would you catch it somewhere else, like try/catch around the function call? How do I know when to propagate and when to catch? – patterned Dec 17 '13 at 21:28
  • It's actually quite simple: don't catch anything. Wrap any checked exception into `RuntimeException` and throw again. *Only* when you have a clear picture of something being not to your liking with that approach, do something about it. – Marko Topolnik Dec 17 '13 at 21:31
  • I would say that it would be ok to catch a FileNotFoundException and reprompt the user for a good file, but if I were to do that, I would separate the logic of trying to open the file from trying to read from the file. – Jazzy Josh Dec 17 '13 at 21:54
  • 3
    @JazzJosh *If*, and it is a big *if*, there was actually any user prompted for the filename, then it would make sense. Of all `new File()` calls written, maybe 0.1% are actually based on user input. – Marko Topolnik Dec 17 '13 at 21:57
  • Yep, I completely agree there. – Jazzy Josh Dec 17 '13 at 21:59
  • @MarkoTopolnik Can you give an example of wrapping a checked exception into `RuntimeException`? Maybe just edit my code for simplicity. – patterned Dec 17 '13 at 22:16
  • I can give it here because it's a one-liner: `throw new RuntimeException(e);` – Marko Topolnik Dec 17 '13 at 22:17
  • Or, the complete idiom: `try {...} catch (RuntimeException e) {throw e;} catch (Exception e) {throw new RuntimeException(e);}`---write this around any block of code which declares checked exceptions. – Marko Topolnik Dec 17 '13 at 22:19
  • Why are you explicitly catching `RuntimeException`, here? I thought it was implied, in a sense? It's unchecked so there is no need, right? – patterned Dec 17 '13 at 22:46
  • 2
    But see that I handle the `RuntimeException` differently: I rethtrow it directly, without wrapping. If I didn't write this, all unchecked exceptions would have been needlessly wrapped into another `RuntimeException`. – Marko Topolnik Dec 18 '13 at 06:46
  • Is this rule applicable for all kinds of exceptions? It is recommended to throw a RuntimeException? @MarkoTopolnik – MaheshVarma Dec 19 '13 at 12:09
  • @MaheshVarma I'm not sure what you mean by *kind* of exception. It is applicable to all exception *classes*, but if, on the program logic level, the exception is not of the "abort the unit of work" kind, then you would catch it, handle appropriately, and not rethrow. This is quite rare in practice, which is why I consider the above as the *default* way to go about it. – Marko Topolnik Dec 19 '13 at 12:12
  • May I know in your experience, have u got any situation where you catched the Exception and handled appropriately? I am asking due to lack of experience. @MarkoTopolnik – MaheshVarma Dec 20 '13 at 04:13
  • @MaheshVarma Again not sure what you are asking. I routinely catch Excption (Throwable, in fact---even wider) at the place where I implement my exception barrier. Each thread needs its own so there can be several such places in the code. – Marko Topolnik Dec 20 '13 at 06:25
6

The difference is there could be other problems inside the code of your try block that could throw other types of Exceptions including subclasses of RuntimeException (which don't have to be declared).

If you just catch Exception, then you will catch all of those other errors too which may hide a different problem. Also your code inside the catch block can't assume the Exception happened due to an IOException since any kind of exception will be caught.

dkatzel
  • 31,188
  • 3
  • 63
  • 67
3

As a followup to dkatzel's answer, let's assume you start to read from the file in the same try block and the file tells you which value in a array of options to use:

String toPrint = {"Hi", "World", "I'm", "A", "String", "Array"};
try{
    BufferedReader reader = new BufferedReader( new FileReader("foo.bar") );
    String line = reader.readLine();
    System.out.println(toPrint[Integer.parseInt(line)]);

}
catch(Exception e){
    println( e.getMessage() );
}

Now you have absolutely no idea what really went wrong except through the stack trace. You can't handle any fixable problems. You can't tell in code whether the file doesn't exist (FileNotFoundException), you don't have access to the file, (IOException), if the first line wasn't an Integer (NumberFormatException), or the number was bigger than the array length (ArrayIndexOutOfBoundsException). If you wanted to print a default value if you couldn't read the number, you could instead catch a NumberFormatException and print the value instead of having to quit the entire program.

I'll admit this is a pretty contrived example, but it should give you an explanation of why catching Exception is bad. Marko also has a very good answer, stating that it usually is better to let the exception propagate up (especially with RuntimeExceptions) than to create a bunch of messy code trying to deal with every single problem that can happen.

Jazzy Josh
  • 272
  • 1
  • 7
  • 1
    Actually, I think it's a great example. This is why it's so common for people to just use Exception in quick and dirty hacking. It's easy to just parse a stacktrace real quick. However, in a production environment when you want the app to actually try and handle exceptions (so it will keep going instead of crashing and burning), this is exactly why you do NOT want to just snag them all right there. – Brian Knoblauch Dec 17 '13 at 21:28
  • 1
    @BrianKnoblauch It is very rarely meaningful to try to recover from random things which can go wrong. All we do is abort the current unit of work and ensure proper cleanup so that the rest of the application doesn't feel a thing. When exceptions are being caught at all, it is usually when they don't signal problems, but *expected* conditions, such as "no such row in the database". – Marko Topolnik Dec 17 '13 at 21:37
  • @MarkoTopolnik So are you speaking about [this](http://stackoverflow.com/a/3540710/3080400) methodology? Specifically "checked exceptions lead to bad code and should therefore not be used". – patterned Dec 17 '13 at 22:11
  • 1
    @patterned I'm not speaking about it right here, but that is my sentiment, yes. Not only are checked exceptions bad, the worst irony is that they were invented to help the unskilled programmer do the right thing, whereas in reality it takes a true expert to avoid the damage they do to code. – Marko Topolnik Dec 17 '13 at 22:16
1

What if you want to do a different action with different exceptions? You can make a catch block for IOException and for example, make it show a message box. Then make another catch block for a FileNotFoundException and make it create a new file and try to open it again, or even rethrow the exception. Hope I explained myself correctly. Cheers!

Mateo Velenik
  • 804
  • 1
  • 10
  • 22
0

The reason is whenever you program, you have to think about all the possibilities and it is useful to do something for a specific error. Exception is a catch all method of catching errors and will handle all exceptions the same. IOException will catch any IO Exceptions so it will treat file not found and and other IO Exception (like EOFException) the same. FileNotFoundException will only catch file not found exceptions so you can handle it instead of just logging it.

Some errors will happen and being able to handle each individual case keeps your program running. In this case, file not found can make you select another file so the program doesn't crash and it handles the situation.

Dom
  • 1,687
  • 6
  • 27
  • 37
0

FileNotFoundException is an IOException which is an Exception

You are right. But if you catch Exception objects you will catch any exception triggered by your code, not only the FileNotFound exception.

Let's say that your code can throw more than one kind of exception:

try {
    /*
     * Code, code and more code
     */
} catch(ExceptionType1 e) {
        System.err.println("Something went wrong! It is a type 1 exception");
} catch(ExceptionType2 e) {
        System.err.println("Something went wrong! It is a type 2 exception");
} catch(Exception e) {
        System.err.println("Something went wrong! It is not any of the known exception types");
}

Compare the above possibility with this:

try {
    /*
     * Code, code and more code
     */
} catch(Exception e) {
        System.err.println("Something went wrong! Can be exception type 1, 2 or something else");
}

As you can see, differentiating the exception types can help you understand what went wrong in your code.

Barranka
  • 20,547
  • 13
  • 65
  • 83