23

In previous versions of java, rethrowing an exception was treated as throwing the type of the catch parameter.

For example:

public static void test() throws Exception{
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (Exception e) {
        System.out.println("Caught exception: " + e.getMessage());
        throw e;
    }
}

In Java 7, you can be more precise about the exception being thrown, if you declare the exception final:

//(doesn't compile in Java<7)
public static void test2() throws ParseException, IOException{
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (final Exception e) {
        System.out.println("Caught exception: " + e.getMessage());
        throw e;
    }
}

My question: The docs say that I need to declare the Exception final. But if I don't, the code above still compiles and works. Am I missing something?

References:

Project Coin: multi-catch and final rethrow
Add more flexible checking for rethrown exceptions

dogbane
  • 266,786
  • 75
  • 396
  • 414
  • The exception parameter in the catch is implicitly final. You don't need to explicitly state it as final. You can, obviously, but you don't have to. – tapavko May 21 '22 at 18:45

3 Answers3

25

I believe I saw a tweet from Josh Bloch saying that the "final" restriction had been lifted late on. I'll see if I can find a post about it, but I suspect it's just that any "early" documentation you read is now inaccurate.

EDIT: I can't find the exact "it's changed" post, but the Java 7 documentation states shows an example with it not being final. It talks about exception variables being implicitly final when a catch block declares more than one type, but that's slightly separate.

EDIT: I've now found the source of my confusion, but it's an internal mailing list post :( Anyway, it doesn't have to be declared as final, but I believe the compiler treats it as implicitly final - just like in the multi-catch scenario.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 6
    Hey @jon-skeet , I know it's a +1y old post, but one thing on that last edit: in this scenario, if `e` is not declared `final`, the compiler **won't** _implicitly_ treat it as `final` (as in multi catch). However, if the `e` reference is changed, then `Exception` has to be included in the `throws` clause. – betomontejo Sep 02 '12 at 20:10
  • @betomontejo BullsEye. – Kumar Abhinav Sep 22 '14 at 15:16
4

The reason why both compile is that an exception in a uni catch clause that is not subsequently modified is implicitly final (JLS 14.20).

So for your example not to compile, you need to modify e in some way, for example:

public static void test2() throws ParseException, IOException {
    DateFormat df = new SimpleDateFormat("yyyyMMdd");
    try {
        df.parse("x20110731");
        new FileReader("file.txt").read();
    } catch (Exception e) {
        if (e instanceof ParseException) {
            e = new ParseException("Better message", 0);
        } else {
            e = new IOException("Better message");
        }
        System.out.println("Caught exception: " + e.getMessage());
        throw e; //does not compile any more
    }
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Related: http://stackoverflow.com/questions/12051791/is-there-ever-a-reason-to-not-use-the-final-keyword-when-catching-an-exception/12051907#12051907 – assylias Aug 21 '12 at 10:22
0

Without the final it is still valid java. You just lose the benefit of it being 'precise'.

Brett Walker
  • 3,566
  • 1
  • 18
  • 36
  • 1
    I think you are missing the thrown exceptions bit of test2() - it *IS* more precise, so a "throw Exception" would normally fail. – Maarten Bodewes Jul 31 '11 at 22:38