简体   繁体   中英

Who catch exception, arise in close method?(try-with-resources)

interface AutoClosable has following method declaration:

void close()  throws Exception

Thus we see that method close can throws Exception.

When I write code try-with resources it is looks like this:

private static void printFileJava7() throws IOException {

    try(FileInputStream input = new FileInputStream("file.txt")) {

        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }
    }
}

At this code is absent Exception handling.

I don't understand what happens if close method throws exception.

Java catches and suppresses exceptions thrown by the close method in a try-with-resources block.

You can read more about this here, see in particular the paragraph after the second code sample. http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

The key to this particular scenario is the "supressed exception".

"Whenever an exception is thrown within the body, and then followed by an exception thrown by the try-with-resources statement, only the exception thrown in the body of the try is eligible to be caught by the exception handling code. All other exceptions are considered supressed exceptions"

A concept that is new with Java 7.SO you will get the same output as when only the printfileJava7 class throws an exception, since the CloseException thrown by the close() method would be suppressed.

Please refer to When two exceptions are thrown by the try-with-resources construct link.Which have taken exact scenario what You have asked

You are right that close() method defined in AutoClosable throws exception. However other interface named Closable that extends AutoClosable redefines this method as following:

void close() throws IOException

All IO related classes implement Closable , so their close() method throws IOException . But your method throws it too, so in your code no-one catches this exception. As always it will be caught by upper layer of your application or by JVM itself if no-one catches it before.

From the jls about Compile-Time Checking of Exceptions

When interfaces are involved, more than one method declaration may be overridden by a single overriding declaration. In this case, the overriding declaration must have a throws clause that is compatible with all the overridden declarations (§9.4.1).

So when you have something like

static class AC implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new Exception("btooom!");
    }
    public void ac() {
        System.out.println("no");
    }
}

public static void main(String[] args) throws Exception {
    try(AC ac = new AC()) {
        ac.ac();
    }
}

then you are forded to either add a catch clause to the surrounding try block or add a throws declaration.

In the case of FileInputStream and to apply what the jsl states, the AutoCloseable 's close method is overriden from Closeable 's, hence you only have to catch an IOException or add it to throws clause.

Further the javadocs of AutoCloseable#close states

While this interface method is declared to throw Exception, implementers are strongly encouraged to declare concrete implementations of the close method to throw more specific exceptions, or to throw no exception at all if the close operation cannot fail.

You need to have a catch block followed by try in the method printFileJava7(). If you don't want to catch it here, you need handle it in the method which calls the method printFileJava7(). We have to catch in one of the layers otherwise it will be propagated back to the calling client.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM