Подтвердить что ты не робот

Захватывает ли Java try-with-resources ошибки или просто исключения?

У меня есть некоторые тесты junit, которые создают некоторые ресурсы, которые также должны быть закрыты.

Один из способов реализации этой логики - использовать подход @Before и @After.

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

class UserCreatorTestUtil implements AutoClosable {
  User create() {...}
  void close() {...}
}

Все дело в том, что объект закрывается, вместо того, чтобы забывать закрыть его в @After.

Использование должно быть:

@Test
void test() {
  try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
    User user = userCreatorTestUtil.create();
    // Do some stuff regarding the user phone
    Assert.assertEquals("123456789", user.getPhone());
  }
}

Проблема заключается в том, что ключевое слово junit assert выбрасывает Error - not Exception.

Будет ли try-with-resource "улавливать" Error и вызывать метод close?

* Не удалось найти ответ в документации try-with-resources.

4b9b3361

Ответ 2

Псевдокод базового оператора try-with-resources (cf Java Language Specification §14.20.3.1):

final VariableModifiers_minus_final R Identifier = Expression;
Throwable #primaryExc = null;

try ResourceSpecification_tail
    Block
catch (Throwable #t) {
    #primaryExc = #t;
    throw #t;
} finally {
    if (Identifier != null) {
        if (#primaryExc != null) {
            try {
                Identifier.close();
            } catch (Throwable #suppressedExc) {
                #primaryExc.addSuppressed(#suppressedExc);
            }
        } else {
            Identifier.close();
        }
    }
}

Как вы видите, он ловит Throwable not Exception, который включает Error, но только для получения основного исключения, чтобы добавить в качестве исключенных исключений все исключения, которые произошли при закрытии ресурсов.

Вы также можете заметить, что ваши ресурсы закрыты в блоке finally, что означает, что они будут закрыты независимо от того, что происходит (за исключением случая System.exit, конечно, поскольку оно завершает текущий запустив виртуальную машину Java) даже в случае, если бросается Error или любой подкласс класса Throwable.

Ответ 3

Try-with-resources ничего не поймают.

Однако вы можете прикрепить блок catch к концу блока try-with-resources, чтобы поймать любые типы Throwable, которые вам нравятся:

try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
  // ... Whatever
} catch (RuntimeException e) {
  // Handle e.
} catch (Exception | Throwable t) {
  // Handle t.
}

Ответ 4

Идея try-with-resources заключается в том, чтобы убедиться, что ресурсы должны быть закрыты.

Проблема с обычными операторами try-catch-finally заключается в том, что пусть ваш блок try генерирует исключение; теперь вы обычно обрабатываете это исключение в блоке finally.

Теперь предположим, что исключение происходит и в блоке finally. В этом случае исключение, вызванное попыткой catch, потеряно, и генерируется исключение, сгенерированное в блоке finally.

try {
    // use something that using resource
    // e.g., streams
} catch(IOException e) {
   // handle 
} finally {
    stream.close();
    //if any exception occurs in the above line, than that exception
    //will be propagated and the original exception that occurred
    //in try block is lost.
}

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

Сравните это с этим:

try (InputStream inputStream= new FileInputStream("C://test.txt")){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

в приведенном выше фрагменте кода автоматически вызывается метод close(), и если этот метод close() также генерирует любое исключение, то это исключение автоматически будет подавлено.

Смотрите также: Спецификация языка Java 14.20.3

Ответ 5

Заблуждение на вашем конце: try-with-resources делает не сделать catch.

Он делает окончательный наконец, поэтому тип "проблемы" не имеет значения.

Для получения дополнительной информации см. JLS!