Пытается ли Java с ресурсами поймать ошибки или просто исключения?


у меня есть некоторые тесты 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's phone
    Assert.assertEquals("123456789", user.getPhone());
  }
}

проблема в том, что ключевое слово JUnit assert выбрасывает Error - не Exception.

будет ли попытка с ресурсом "поймать"Error и вызвать метод close?

* не смог найти ответ в try-with-resources documentation.

5 51

5 ответов:

Это не catch ничего. Но это так finally закрыть все ресурсы.

finally блоки запускаются даже при возникновении ошибки.

псевдокод базового try-with-resources оператор is (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 не 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. В таком случае исключение, вызванное try catch,проиграл и исключение, созданное в finally блок получает пропагандируемый.

try {
    // use something that's 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 the 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 делает не сделать лови.

Это финалнаконец-то, поэтому такой "проблемы" не имеет значения.

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