Ernest Hilvano
Ernest Hilvano

Reputation: 513

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

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.

Upvotes: 4

Views: 195

Answers (2)

Erwin Bolwidt
Erwin Bolwidt

Reputation: 31269

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");
  }
}

Upvotes: 1

Reinstate Monica
Reinstate Monica

Reputation: 2798

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.

Upvotes: 10

Related Questions