Рубрики
Без рубрики

Сценарии исключений для Java-попыток с ресурсами

Вы когда-нибудь сталкивались с исключением, вызванным блоком “попробуйте с ресурсами”, и задавались вопросом, как это работает? T… С тегами java, для начинающих, учебник.

Вы когда-нибудь сталкивались с исключением, вызванным блоком “попробуйте с ресурсами”, и задавались вопросом, как это работает? В этой статье рассматривается поведение try-with-resources в различных сценариях и объясняется, что происходит.

Поддержка try-с-ресурсами была добавлена в java 7 и улучшена в java 9. Блок “Попытка с ресурсами” может автоматически закрывать ресурсы по завершении выполнения блока. Существует множество различных сценариев, в которых попытка с использованием ресурсов вызовет исключения. В этой статье рассматриваются эти сценарии.

Если вы следуете вместе с примерами тестов, то Тестовый ресурс класс прикреплен в нижней части этой статьи.

Тестовый ресурс – это макет объекта, используемый для имитации ресурса. Он может быть настроен на сбой работы() и закрыть() методы. и закрыть() методы. Метод

и ||закрыть()|| методы. Метод ||create Failure()|| имитирует сбой при создании ресурса в блоке try. Объявить и инициализировать ресурс

и закрыть() методы. Метод

try(var r = new TestResource()) {
  //work with resource here
}

и закрыть()

Сначала объявляется и инициализируется r . Сначала объявляется и инициализируется r . После выполнения блока try

creating resource "resource"
closing resource "resource"

Сначала объявляется и инициализируется ||r||. После выполнения блока try r|| автоматически закрывается и выходит за пределы области действия. объявлять только ресурс

Сначала объявляется и инициализируется ||r||. После выполнения блока try r|| автоматически закрывается и выходит за пределы области действия. объявлять ресурс только в java 7 ресурс, который необходимо объявить и инициализировать в спецификации ресурса. Сначала объявляется и инициализируется ||r||. После выполнения блока try r|| автоматически закрывается и выходит за пределы области действия. объявлять ресурс только в java 7 ресурс, который необходимо объявить и инициализировать в спецификации ресурса. Поскольку инициализация java 9 не требуется, пока переменные являются фактически окончательными. Сначала объявляется и инициализируется ||r||. После выполнения блока try r|| автоматически закрывается и выходит за пределы области действия. объявлять ресурс только в java 7 ресурс, который необходимо объявить и инициализировать в спецификации ресурса. Поскольку инициализация java 9 не требуется, пока переменные являются фактически окончательными. Вот пример:

try(r) {
  //work with resource here
}

Сначала объявляется и инициализируется ||r||. После выполнения блока try r|| автоматически закрывается и выходит за пределы области действия. объявлять ресурс только в java 7 ресурс, который необходимо объявить и инициализировать в спецификации ресурса. Поскольку инициализация java 9 не требуется, пока переменные являются фактически окончательными. Вот пример: несколько ресурсов

В блоке “попробуйте с ресурсами” можно использовать несколько ресурсов.

try(var r1 = new TestResource("r1"); var r2 = new TestResource("r2")) {
    //work with resource here
}

Ресурсы создаются по порядку и закрываются в обратном порядке.

creating resource "r1"
creating resource "r2"
closing resource "r2"
closing resource "r1"

когда создание завершается неудачей с одним ресурсом

Вот пример того, что происходит, когда создание терпит неудачу.

try(var r1 = createFailure()) {
    //work with resource here
}

Возникает исключение.

create failure
java.io.IOException: create failure
    at com.github.moaxcp.trywithresources.TestResource.createFailure(TestResource.java:12)
    at com.github.moaxcp.trywithresources.TestTryWithResources.creat_fails(TestTryWithResources.java:35)

Исключение может быть поймано с помощью блока catch.

try(var r1 = createFailure()) {
    //work with resource here
} catch (IOException e) {
    System.out.println("caught exception " + e);
}

Исключение выбрасывается и перехватывается.

create failure
caught exception java.io.IOException: create failure

при сбое создания с несколькими ресурсами

Другой сценарий – это то, что происходит, когда создание завершается неудачей с несколькими ресурсами.

try(var r1 = new TestResource("r1"); var r2 = createFailure()) {
    //work with resource here
} catch (IOException e) {
    System.out.println("caught exception " + e);
}

r1 создается, r2 не удается создать, затем r1 закрывается, а затем выполняется блок catch.

creating resource "r1"
create failure
closing resource "r1"
caught exception java.io.IOException: create failure

Обратите внимание что r1 закрывается до выполнения блока catch.

Теперь, когда мы знаем механику создания ресурса в блоке “Попробуйте с ресурсами”, давайте рассмотрим работу с ресурсами внутри блока.

Работа с одним ресурсом

try(var r = new TestResource()) {
    r.work();
}

В этом случае ресурс создается, работа выполняется, и ресурс закрывается.

creating resource "resource"
performing work with resource "resource"
closing resource "resource"

когда работа терпит неудачу

Что происходит с методом work() , вызывающим исключение? Это можно сделать, установив флаг сбоя работы в true на Тестовом ресурсе .

try(var r = new TestResource(true, false)) {
    r.work();
}

При сбое работы ресурс должен быть закрыт, и тогда исключение может быть перехвачено или выдано.

creating resource "resource"
performing work with resource "resource"
work failure with resource "resource"
closing resource "resource"

work failure with resource "resource"
java.io.IOException: work failure with resource "resource"
    at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47)
    at com.github.moaxcp.trywithresources.TestTryWithResources.work_with_resource_fails(TestTryWithResources.java:68)

В этом случае, если бы был блок catch, он был бы выполнен после закрытия ресурса.

при сбоях в работе с несколькими ресурсами

При сбое работы с несколькими ресурсами ресурсы закрываются в обратном порядке, и исключение перехватывается или выбрасывается.

try(var r1 = new TestResource("r1", false, false); var r2 = new TestResource("r2", true, false)) {
    r1.work();
    r2.work();
}

Здесь r2 настроен на сбой при вызове метода work() .

creating resource "r1"
creating resource "r2"
performing work with resource "r1"
performing work with resource "r2"
work failure with resource "r2"
closing resource "r2"
closing resource "r1"

work failure with resource "r2"
java.io.IOException: work failure with resource "r2"
    at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47)
    at com.github.moaxcp.trywithresources.TestTryWithResources.work_with_multiple_resources_fails(TestTryWithResources.java:76)

Как вы можете видеть, при сбое r2.work() ресурсы закрываются в обратном порядке и создается исключение.

Как показано ранее, блок “попытка с ресурсами” автоматически закроет ресурс, но что произойдет, если закрытие завершится неудачно?

при сбое закрытия с одним ресурсом

Сбой закрытия может быть достигнут путем установки флага Сбой закрытия в true на Тестовом ресурсе .

try(var r = new TestResource(false, true)) {
    r.work();
}

При сбое закрытия выдается исключение.

creating resource "resource"
performing work with resource "resource"
closing resource "resource"
close failure with resource "resource"

close failure with resource "resource"
java.io.IOException: close failure with resource "resource"
    at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56)
    at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_resource_fails(TestTryWithResources.java:84)

При сбое закрытия с двумя ресурсами

Здесь r1 и r2 не смогут закрыться.

try(var r1 = new TestResource("r1", false, true); var r2 = new TestResource("r2", false, true)) {
    r1.work();
    r2.work();
}

Поскольку ресурсы закрываются в обратном порядке, исключение из r2 будет подавлять исключение из r1 .

creating resource "r1"
creating resource "r2"
performing work with resource "r1"
performing work with resource "r2"
closing resource "r2"
close failure with resource "r2"
closing resource "r1"
close failure with resource "r1"

close failure with resource "r2"
java.io.IOException: close failure with resource "r2"
    at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56)
    at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_two_resources_fails(TestTryWithResources.java:92)
Suppressed: java.io.IOException: close failure with resource "r1"
        at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56)
        at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_two_resources_fails(TestTryWithResources.java:89)

Обратите внимание – Исключение из закрытия r1 подавляется исключением из r2 .

Теперь мы переходим к интересному сценарию.

try(var r1 = new TestResource("r1", true, true); var r2 = new TestResource("r2", true, true)) {
    r1.work();
}

В этом случае работа завершится неудачей, но также произойдет закрытие двух ресурсов.

creating resource "r1"
creating resource "r2"
performing work with resource "r1"
work failure with resource "r1"
closing resource "r2"
close failure with resource "r2"
closing resource "r1"
close failure with resource "r1"

work failure with resource "r1"
java.io.IOException: work failure with resource "r1"
    at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47)
    at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:98)
...
    Suppressed: java.io.IOException: close failure with resource "r2"
        at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56)
        at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:97)
        ... 88 more
    Suppressed: java.io.IOException: close failure with resource "r1"
        at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56)
        at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:97)
        ... 88 more

Здесь происходит сбой работы, и два близких сбоя подавляются.

Попытка с ресурсами – очень полезный инструмент при работе с ресурсами. Это особенно полезно при работе с несколькими ресурсами. Это избавляет разработчика от необходимости писать правильный закрывающий код. Он также делает доступными подавленные исключения, чтобы разработчики точно знали, какие сбои произошли. В этой статье описываются различные механизмы использования ресурсов в разных сценариях. Можете ли вы придумать какие-либо другие сценарии для использования ресурсов?

Прежде чем я начну показывать примеры, необходимо указать некоторый код для тестового ресурса и неисправного заводского метода.

class TestResource implements AutoCloseable {
    private final String name;
    private final boolean workFailure;
    private final boolean closeFailure;

    public static TestResource createFailure() throws IOException {
        System.out.println("create failure");
        throw new IOException("create failure");
    }

    public TestResource() {
        name = "resource";
        System.out.println("creating resource \"" + name + "\"");
        workFailure = false;
        closeFailure = false;
    }

    public TestResource(String name) {
        System.out.println("creating resource \"" + name + "\"");
        this.name = name;
        workFailure = false;
        closeFailure = false;
    }

    public TestResource(boolean workFailure, boolean closeFailure) throws IOException {
        this.name = "resource";
        System.out.println("creating resource \"" + name + "\"");
        this.workFailure = workFailure;
        this.closeFailure = closeFailure;
    }

    public TestResource(String name, boolean workFailure, boolean closeFailure) throws IOException {
        System.out.println("creating resource \"" + name + "\"");
        this.name = name;
        this.workFailure = workFailure;
        this.closeFailure = closeFailure;
    }

    public void work() throws IOException {
        System.out.println("performing work with resource \"" + name + "\"");
        if(workFailure) {
            System.out.println("work failure with resource \"" + name + "\"");
            throw new IOException("work failure with resource \"" + name + "\"");
        }
    }

    @Override
    public void close() throws IOException {
        System.out.println("closing resource \"" + name + "\"");
        if(closeFailure) {
            System.out.println("close failure with resource \"" + name + "\"");
            throw new IOException("close failure with resource \"" + name + "\"");
        }
    }
}

Оригинал: “https://dev.to/moaxcp/exception-scenarios-for-java-s-try-with-resources-63m”