Кто ловит исключение, возникающее в закрытом методе? (попробуйте с ресурсами)

интерфейс AutoClosable имеет следующее объявление метода:

void close()  throws Exception

Таким образом мы видим, что метод close может генерировать Exception.

Когда я пишу код try-with resources, он выглядит так:

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

В этом коде отсутствует обработка исключений.

Я не понимаю, что происходит, если метод close вызывает исключение.


person gstackoverflow    schedule 13.07.2014    source источник


Ответы (5)


Java перехватывает и подавляет исключения, генерируемые методом close в блоке try-with-resources.

Подробнее об этом можно прочитать здесь, см., в частности, абзац после второго примера кода. http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

person Dave Morrissey    schedule 13.07.2014
comment
Я думаю, это то, что ищет ОП. +1. Я добавляю цитату из документа, на который вы ссылаетесь, чтобы, если ОП хочет получить подавленное исключение, он знал, как это сделать: You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block. - person ThanksForAllTheFish; 13.07.2014

Вы правы, что метод close(), определенный в AutoClosable, выдает исключение. Однако другой интерфейс с именем Closable, расширяющий AutoClosable, переопределяет этот метод следующим образом:

void close() throws IOException

Все классы, связанные с вводом-выводом, реализуют Closable, поэтому их метод close() выдает IOException. Но ваш метод тоже выбрасывает его, поэтому в вашем коде это исключение никто не перехватывает. Как всегда, он будет перехвачен верхним уровнем вашего приложения или самой JVM, если никто не перехватил его раньше.

person AlexR    schedule 13.07.2014
comment
а если будет ловить IOException внутри моего метода? Буду ли я перехватывать Exceptions throws внутри метода закрытия? - person gstackoverflow; 13.07.2014

Из jls о проверке во время компиляции Исключения

Когда задействованы интерфейсы, более одного объявления метода может быть переопределено одним объявлением переопределения. В этом случае переопределяющее объявление должно иметь предложение throws, совместимое со всеми переопределенными объявлениями (§9.4.1).

Итак, когда у вас есть что-то вроде

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

тогда вам придется либо добавить предложение catch в окружающий блок try, либо добавить объявление throws.

В случае FileInputStream и применить то, что jsl указывает, что AutoCloseable закрывается метод переопределен из Closeable, поэтому у вас есть только чтобы поймать IOException или добавить его в броски пункт.

Далее javadocs AutoCloseable#close состояния

Хотя этот интерфейсный метод объявлен для генерации исключения, разработчикам настоятельно рекомендуется объявлять конкретные реализации метода close для создания более конкретных исключений или вообще не создавать исключений, если операция закрытия не может завершиться ошибкой.

person A4L    schedule 13.07.2014

Ключом к этому конкретному сценарию является «подавленное исключение».

«Всякий раз, когда в теле выдается исключение, а затем следует исключение, генерируемое оператором try-with-resources, только исключение, выброшенное в теле попытки, может быть перехвачено кодом обработки исключений. Все остальные исключения считаются подавленными исключениями"

Концепция, которая является новой для Java 7. Таким образом, вы получите тот же вывод, что и когда только класс printfileJava7 выдает исключение, поскольку CloseException, созданное методом close(), будет подавлено.

См. Если два исключения выдаются ссылка конструкции try-with-resources. Которая приняла точный сценарий, который вы просили

person Abhijeet Panwar    schedule 13.07.2014

Вам нужно иметь блок catch, за которым следует try в методе printFileJava7(). Если вы не хотите ловить его здесь, вам нужно обработать его в методе, который вызывает метод printFileJava7(). Мы должны поймать один из слоев, иначе он будет передан вызывающему клиенту.

person Venkat    schedule 27.01.2016