Why it is okay in java 7 to catch an IOException even if IOException will never be thrown

200 Views Asked by At
public class SampleCloseable implements AutoCloseable {

    private String name;

    public SampleCloseable(String name){
        this.name = name;
    }

    @Override
    public void close() throws Exception {
        System.out.println("closing: " + this.name);
    }
}

and the main class

public class Main{

    public static void main(String args[]) {
      try(SampleCloseable sampleCloseable = new SampleCloseable("test1")){

          System.out.println("im in a try block");

      } catch (IOException  e) {
          System.out.println("IOException is never thrown");

      } catch (Exception e) {

      } finally{
          System.out.println("finally");
      }

    }
}

But when i removed the throws exception on close() method inside SampleCloseable i am getting a compiler error saying that IOException is never thrown in the corresponding try block.

2

There are 2 best solutions below

0
On

Because you're throwing a generic Exception. Since an IOException inherits from Exception, it might be thrown by the close() method. The caller doesn't know that it doesn't actually get thrown. It only sees the method signature that says that it could.

In fact, the close() method is free to throw any Exception of any kind. Of course that's bad practice, you should specify what specific Exceptions you're throwing.

0
On

Your confusion may that around the fact the in Java 7, the exception that is [declared to be] thrown from the close method is thrown inside the try block, so your catch block has to catch it as well.

Your close method is declared to throw an Exception, so your catch blocks have to catch that, or the method has to be declared to throw Exception.

And since IOException is a subclass of Exception, you are of course allowed to try and catch that as well, as long as your also catch/declare Exception itself.

See JLS 14.20.3.2:

The meaning of an extended try-with-resources statement [...] is given by the following translation to a basic try-with-resources statement (§14.20.3.1) nested inside a try-catch or try-finally or try-catch-finally statement.

Your code is effectively translated to the below. Although a bit longish, it should be clear from the below what's happening in your code.

public static void main(String args[]) {
  try {
      Throwable primaryEx = null ;
      SampleCloseable sampleCloseable = new SampleCloseable("test1")
      try {
          System.out.println("im in a try block");
      } catch (Throwable t) {
          primaryEx = t;
          throw t;
      } finally {
        if (sampleCloseable != null) {
        if (primaryEx != null) {
            try {
                sampleCloseable.close();
            } catch (Throwable suppressedExc) {
                primaryEx.addSuppressed(suppressedExc);
            }
        } else {
            sampleCloseable.close();
        }
      }
  } catch (IOException  e) {
      System.out.println("IOException is never thrown");

  } catch (Exception e) {

  } finally{
      System.out.println("finally");
  }
}