Java unreachable catch block compiler error
Asked Answered
L

7

18

Why in Java can we catch an Exception even if it is not thrown, but we can't catch it's subclass (except for "unchecked" RuntimeExceptions and it subclasses). Example code:

class Test {
    public static void main(String[] args) {
        try {
            // do nothing
        } catch (Exception e) {
            // OK           
        }

        try {
            // do nothing
        } catch (IOException e) {
               // COMPILER ERROR: Unreachable catch block for IOException.
               //This exception is never thrown from the try statement body
        }       
    }
}

Any ideas?

Larrup answered 5/5, 2011 at 14:57 Comment(2)
that means there is nothing to catch (no error) i dont see the issueExemption
You should read the Java Language Specification, or at least a good Java tutorial.Eisenstark
P
30

A RuntimeException could be thrown by any code. In other words, the compiler can't easily predict what kind of code can throw it. A RuntimeException can be caught by a catch(Exception e) block.

IOException, however, is a checked exception - only method calls which are declared to throw it can do so. The compiler can be (reasonably) confident that it can't possible occur unless there are method calls which are declared to throw it.

The Java compiler simply doesn't consider the "there's no code at all within the try block" situation - it always allows you to catch unchecked exceptions, as in all reasonable scenarios there will be code which could potentially throw an unchecked exception.

From section 14.21 of the JLS:

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

  • Some expression or throw statement in the try block is reachable and can throw an exception whose type is assignable to the parameter of the catch clause C. (An expression is considered reachable iff the innermost statement containing it is reachable.)
  • 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.

Arguably the compiler should realize that there are no expressions within the try block in your first case... it looks like this is still an unreachable catch clause, to me.

EDIT: As noted in comments, section 14.20 contains this:

It is a compile-time error if a catch clause catches checked exception type E1 but there exists no checked exception type E2 such that all of the following hold:

  • E2 <: E1
  • The try block corresponding to the catch clause can throw E2
  • No preceding catch block of the immediately enclosing try statement catches E2 or a supertype of E2.

unless E1 is the class Exception.

So it looks like that's what you're actually running foul of, but the spec isn't as clear as it could be in terms of unreachable catch blocks in 14.21.

Pigskin answered 5/5, 2011 at 15:1 Comment(2)
I think the solution is in § 14.20, which explicitly says that Exception excempt from the "must be thrown" check: "[...] unless E1 is the class Exception".Divergency
@Joachim: Well found. Will add that to the answer.Pigskin
G
5

IO Exceptions can only be caught if the compiler predicts that there might be something in the code that throws IOException. So you are getting a warning that IO exception is never thrown from the try statement body (since there is nothing in the body of try).

Gruesome answered 12/2, 2014 at 7:25 Comment(0)
R
3

Because for checked exceptions the method that is throwing them, must explicitly state this fact by 'throws' keyword, thus if a block doesn't have the 'throws IOException' in your case, the compiler has the information it is impossible for an IOException to be thrown, so the whatever you do after catching, it would be unreachable.

Rung answered 5/5, 2011 at 15:1 Comment(0)
M
3

You can't catch unthrown checked exceptions because they can't be thrown. You can catch Exception because an unchecked runtime exception IS an Exception and COULD potentially be thrown.

Maurilia answered 5/5, 2011 at 15:1 Comment(0)
D
1

IOException is a checked Exception that is only thrown by IO related code. Since your try block does nothing, nothing IO related will ever happen, IOExceptions will never be thrown, so there is no way the catch block will ever be executed and the compiler don't let you get around with it. As you said, Exception may refer to unchecked Runtime Exceptions that may occur at any moment. That's the main difference between unchecked and checked exceptions, and that is why the compiler don't enforce the code to catch every possible runtime exception.

Doddering answered 5/5, 2011 at 15:4 Comment(0)
L
0

Simply Java assumes that any code line can throw a generic Exception or Throwable, ie. OutOfMemoryException which is an Error rather an Exception. Same applies for NPE.

IOException is a specific exception that can be thrown only by managed code, so if you don't have I/O calls in your catch block your compiler that there is no chance to catch it.

Just to compare to C# world, in C# such code would be compiled but would be a conceptual mistake since if you don't do anything you don't reach the catch block. A tool such as ReSharper can warn you about that.

Lexielexigraphy answered 5/5, 2011 at 15:1 Comment(1)
The difference is that IOException (and all its sub-types) are checked exceptions, so the compiler can find out exactly which statements could throw them. Exception includes RuntimeException and therefore could happen in any statement (as they are unchecked and need not be declared).Divergency
L
0

If we summarize from everyone's comment above, it can be concluded that fully checked exceptions like IOException and it's subclass are meant be to strictly checked by compiler and expected by relevant catch clause to throw. But in case of RuntimeException and Exception or Throwable (which both are partially checked exception, since they have RuntimeException as child/grandchild) compiler simply can't say at compile time and allow it to pass.

So..

try{
  // Empty - valid
} catch(Exception or Throwable or any Runtime Exception ){

}

but

try{
  // Empty - invalid and compile time error
} catch (Any fully checked Exception like IOException, FileNotFoundException, EOF/Interruped etc){

}
Linstock answered 6/1, 2021 at 19:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.