Ответ 1
Это ничего не значит catch
. Но он finally
закрывает все ресурсы.
finally
блоки выполняются даже при ошибке.
У меня есть некоторые тесты 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.
Это ничего не значит catch
. Но он finally
закрывает все ресурсы.
finally
блоки выполняются даже при ошибке.
Псевдокод базового оператора 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
.
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.
}
Идея 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
Заблуждение на вашем конце: try-with-resources делает не сделать catch.
Он делает окончательный наконец, поэтому тип "проблемы" не имеет значения.
Для получения дополнительной информации см. JLS!