Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why java does not detect unreachable catch block if I use multiple catch blocks?

Research following method:

static private void foo()  {
        try {
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

This code compiles good despite last catch block actually unreachable.

Now lets comment throw new FileNotFoundException(); row

execute:

OOOPs! we see

Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body

Strange. Why does java use double standards for these situatons?

update for @Peter Rader

static private void foo(FileNotFoundException f)  {
        try {
            throw f;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

work as well as with constructor invocation

update

I noticed that on different versions of java compiler I see different result of compiling this code.

public class RethowTest {

        public static void main(String[] args)  {
            try {
                throw new FileNotFoundException();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw e;
            }
        }    
}

on my local pc: java 1.7.0_45 -

C:\Program Files\Java\jdk1.7.0_45\bin>javac D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java
D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:15: warning: unreachable catch clause
                } catch (IOException e) {
                  ^
  thrown type FileNotFoundException has already been caught
1 warning

java 1.6.0_38

D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown
                    throw e;
                    ^
1 error

http://www.compileonline.com/compile_java_online.php (Javac 1.7.0_09) -

HelloWorld.java:9: warning: unreachable catch clause
        } catch (IOException e) {
          ^
  thrown type FileNotFoundException has already been caught
1 warning
like image 517
gstackoverflow Avatar asked Sep 02 '14 13:09

gstackoverflow


People also ask

What happens if we have multiple catch blocks?

Whenever an exception object is identified in a try block and if there are multiple catch blocks then the priority for the catch block would be given based on the order in which catch blocks are have been defined. Highest priority would be always given to first catch block.

Can a program have multiple catch blocks in Java?

Java Catch Multiple ExceptionsA try block can be followed by one or more catch blocks. Each catch block must contain a different exception handler. So, if you have to perform different tasks at the occurrence of different exceptions, use java multi-catch block.

Can multiple catch blocks be executed?

No, multiple catch blocks cannot be executed. Once first catch block is catched, it will not read the next block.

Can I execute multiple catch blocks without try will it give me compile time error?

You cannot have multiple try blocks with a single catch block. Each try block must be followed by catch or finally. Still if you try to have single catch block for multiple try blocks a compile time error is generated.


2 Answers

The reachability rules are defined in the Java 8 JLS 14.21 (and Java 7) as follows:

A catch block C is reachable iff both of the following are true:

  • Either the type of C's parameter is an unchecked exception type or Exception or a superclass of Exception, or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the type of C's parameter. (An expression is reachable iff the innermost statement containing it is reachable.)

    See §15.6 for normal and abrupt completion of expressions.

  • There is no earlier catch block A in the try statement such that the type of C's parameter is the same as or a subclass of the type of A's parameter.

Note that the rules DO NOT forbid your example code. The second catch block does not meet the criteria of the second bullet point.

(In the original version of the example, you caught Exception. The reachability reasoning would be different, but the answer is the same - valid code.)

Is this inconsistent? For your example, you could argue that is the case.

Why didn't they address this case in the reachability rules? I don't know. You'd need to ask the Java designers!! However:

  • The formulation of the reachability rules would need to be significantly more complicated to handle this. Extra (unnecessary?) complexity in a specification is a concern.

  • You could argue that this inconsistency doesn't break anything. The reachability rules are really just a way of picking up potential errors in the users code. It doesn't involve type-safety or predictable execution; i.e. stuff that would "break" Java runtime semantics.

  • If they changed the spec now, that would render invalid a small proportion of valid and working Java programs. That's not a good idea, given that stability is one of the main selling points of Java.

On the other hand, I cannot think of a technical reason why they couldn't have addressed this "inconsistency" in the spec.


You noted that some Java compilers give a Warning message on the 2nd catch. That is OK. A Java compiler is allowed to give warnings for things that are (technically) legal Java code.

If they were Errors, that would technically be a compiler bug ... according to my reading of the JLS.

like image 89
Stephen C Avatar answered Oct 25 '22 11:10

Stephen C


The catch (Exception ...) block will catch runtime exceptions. It's never unreachable in principle.

FileNotFoundException is a checked exception. A catch block for it is only reachable if something in the try block throws it, or one of its child classes.

[in response to requests]

like image 40
user207421 Avatar answered Oct 25 '22 11:10

user207421