8

The Java compiler seems inconsistent if there is some code that clearly can not throw an exception, and you write surrounding code that declares that the code can throw that exception.

Consider these code snippets.

Snippet 1

A catch of an exception that is never thrown.

public void g(){
        try {

        } catch (FileNotFoundException e) {//any checked exception

        }

}

It is compile error with message

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

Snippet2

A throws declaration indicating an exception that is never thrown.

public void g() throws FileNotFoundException{
}

It compiles fine.

Therefore, the results of the first code snippet shows that the compiler can calculate if a method can throw an exception listed in the throws list. So it seems the compiler is deliberately not reporting an error for the second snippet. But Why? Why does the compiler allow you to write exceptions in throws section even if it the compiler knows thst those exceptions can not be thrown?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • 1
    The simple answer is "because the spec says so." Speculating a bit, it seems like in the first case, you're running up against Java's decision to make unreachable code an error: the catch block will never catch anything. In the second case, while your method will never actually throw that exception, there's no code that is unreachable because of that. – dlev Mar 24 '14 at 13:30
  • 1
    @dlev You don't understand my question – gstackoverflow Mar 24 '14 at 13:31
  • It may be the case of contract/interface and implementation. You define a method that may throw an exception -> callers may want to handle that exception **if** it occurs. The method may complete normally, it does **not** have to throw an exception every time. In this particular case your implementation will **never** throw an exception, but the method (in any future implementation) still may. – Germann Arlington Mar 24 '14 at 13:35
  • P.S. "Unreachable catch block" seems to be alike to a warning, **not** error because the code still compiles and runs... – Germann Arlington Mar 24 '14 at 13:37
  • @Admins - it is not duplicate of http://stackoverflow.com/questions/22116175/custom-exception-class-shows-unreachable-catch-block-everytime – gstackoverflow Mar 24 '14 at 13:38
  • @Germann Arlington **P.S. "Unreachable catch block" seems to be alike to a warning, not error because the code still compiles and runs.** create main method, create object, invoke method and you get compilation problem – gstackoverflow Mar 24 '14 at 13:43
  • `public class UnreachableCatchBlock { public static void main(String[] args) { UnreachableCatchBlock ucb = new UnreachableCatchBlock(); System.out.println(ucb.getClass().getName() + " started."); ucb.method2(); // ucb.method1(); } private void method1() { try { System.out.println(getClass().getName() + ".method1() started."); } catch (FileNotFoundException e) {//any checked exception } } private void method2() { System.out.println(getClass().getName() + ".method2() started."); } } ` compiles and runs. – Germann Arlington Mar 24 '14 at 14:04
  • It only fails when you try to use/call the method which is not implemented correctly... – Germann Arlington Mar 24 '14 at 14:05
  • @Germann Arlington please write answer - I cannot read this code here – gstackoverflow Mar 24 '14 at 14:09

5 Answers5

11

The compiler allows this because the throws clause of the method is part of the signature of the method, rather than part of its implementation. It is possible that the implementation might change at some point, while keeping the signature the same. An old implementation might have thrown a checked exception, but the new one might not. Or the designer of the signature might have wanted to give the implementer the flexibility to throw a checked exception when that is not always necessary.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
0

Just a try !!

For second case there might be a possibility that some other class overrides this method in the future and a code is written inside that which can throw this exception.

RKC
  • 1,834
  • 13
  • 13
0

Throws does not handle exception, It indicates the throwing exception upwards from where method will be called. In other words it will just pass exception to the caller.

While try...catch block handles the exception, and that is why Java compiler will check if there is any exception to handle which is being caught in catch block or not.

Those are two different thing, One is Throwing and another is Handling the exception and compiler will make his nose tilted on second one only...:p

From the JavaDoc :

Exception handlers can do more than just print error messages or halt the program. They can do error recovery, prompt the user to make a decision, or propagate the error up to a higher-level handler using chained exceptions.

So, by providing try...catch implementation, you are requesting compiler to do some more thing than just printing exception.

Another specific reason :

public void testException() throws FileNotFoundException {
    File file = new File("test.txt");
    System.out.println(file.exists());
    Scanner scanner = new Scanner(file);
}

If you will observe the compiled code of above example by javap -c Test.class you will find an Exception table will be created.

  public static void testException();
    Code:
       0: new           #2                  // class java/io/File
       3: dup           
       4: ldc           #3                  // String test.txt
       6: invokespecial #4                  // Method java/io/File."<init>":(Ljava/lang/String;)V
       9: astore_0      
      10: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      13: aload_0       
      14: invokevirtual #6                  // Method java/io/File.exists:()Z
      17: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
      20: new           #8                  // class java/util/Scanner
      23: dup           
      24: aload_0       
      25: invokespecial #9                  // Method java/util/Scanner."<init>":(Ljava/io/File;)V
      28: astore_1      
      29: goto          37
      32: astore_1      
      33: aload_1       
      34: invokevirtual #11                 // Method java/io/FileNotFoundException.printStackTrace:()V
      37: return        
    Exception table:
       from    to  target type
          20    29    32   Class java/io/FileNotFoundException

So, When compiler won't find any code that is not throwing exception in try block, an compile time error will be there.

and Exception table will not be generated in case of throws.

Not a bug
  • 4,286
  • 2
  • 40
  • 80
0

Since you wanted other views -

Consider two implementations of the same signature in two different subclasses.

For example, (a made up example),

public class StudentLoader {
    public abstract Student readStudentData() throws SQLException, IOException;

    public static void main(String args[]) {
        StudentLoader loader = getStudentLoader (); //may return any subclass instance
        try {
            Student s = loader.readStudentData();
        }
        catch(IOException e) {
            //do something
        }
        catch(SQLException e) {
            //do something
        }
    }
}

public class StudentFileReader extends StudentLoader {
    public Student readStudentData() throws IOException {
        //read from a file
    }
}

public class StudentDBReader extends StudentLoader {
    public Student readStudentData() throws SQLException {
        //read from DB
    }
}

why compiler do allow to write exceptions in throws section even if it can not be thrown?

Even though the subclass implementation StudentDBReader is not throwing IOException, the parent class StudentLoader still has to say throws IOException because other implementations of StudentLoader may throw it. So even though the exception may not be thrown by the method, you have a way of indicating to the caller using StudentLoader reference (that points to either of the two subclasses instance) that the caller must handle these exceptions.

In your snippet 1 showing method g(), there is no scope of inheritance. The code is right there in the try block. If any statement in try is throwing a checked Exception, you will have to handle it. In case of throws clause, scope for inheritance has to be allowed. Compiler cannot decide which version of readStudentData( ) will be called at runtime.

I would expect that compiler should give an error in case of static methods, if Exception mentioned in throws clause is not thrown, since static methods do not participate in inheritance. I am not sure why throws clause in static methods can contain Exceptions which are never thrown in implementation. It will not be overridden anyway, so why not throw error here? There might be something I am missing.

RuntimeException
  • 1,593
  • 2
  • 22
  • 31
0
public class UnreachableCatchBlock {

    public static void main(String[] args) {
        UnreachableCatchBlock ucb = new UnreachableCatchBlock();
        System.out.println(ucb.getClass().getName() + " started.");
//      ucb.method1();
        ucb.method2();
    }

    private void method1() {
        try {
            System.out.println(getClass().getName() + ".method1() started.");
        } catch (FileNotFoundException e) {//any checked exception

        }
    }

    private void method2() {
            System.out.println(getClass().getName() + ".method2() started.");
    }

}

Above code compiles and runs as explained in @Raedwald answer.

I don't suggest this as an answer, just a place to post the code that I attempted to include in comments.

Germann Arlington
  • 3,315
  • 2
  • 17
  • 19
  • it is very strange. It is surprised behaviour for me – gstackoverflow Mar 24 '14 at 15:56
  • As I mentioned earlier and per @Raedwald answer: the signature allows a method to throw exceptions at some point in the future and indicates to any code using the method that it may happen. The fact that it does **not** happen at the moment does **not** violate the contract... – Germann Arlington Mar 24 '14 at 16:03
  • for me surprised that if comment **ucb.method1()** - I don't see compile error – gstackoverflow Mar 24 '14 at 16:05
  • it turns out it is a feature of the Eclipse compiler http://stackoverflow.com/questions/22614515/eclipse-why-dont-i-see-compile-error-if-method-with-unreachable-code-doesnt-i – gstackoverflow Mar 25 '14 at 07:08