问题
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
回答1:
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.
回答2:
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]
回答3:
If you instanciate new FileNotFoundException()
you call the constuctor of the Class FileNotFoundException
. In this constructor a IOException can theroretically be thrown by calling the native method fillInStackTrace
- the compiler may not know whats the content of the Constructor, maybe a IOException
will be thrown.
See this article: https://community.oracle.com/thread/1445008?start=0 in example.
If the compiler looks into the constructor FileNotFoundException()
for every occourcence: its a overhead java neglect for performance.
来源:https://stackoverflow.com/questions/25624317/why-java-does-not-detect-unreachable-catch-block-if-i-use-multiple-catch-blocks