Одной из наиболее полезных функций Java 7 было введение оператора try-with-resources , также известного как автоматическое управление ресурсами ( ARM ). Привлекательность оператора try-with-resources заключается в его обещании «обеспечить закрытие каждого ресурса в конце оператора». «Ресурс» в этом контексте — это любой класс, который реализует AutoCloseable и его метод close () и создается в предложении «try» оператора try-with-resources .
Спецификация языка Java (JLS) описывает заявление примерочных с-ресурсами подробно в разделе 14.20.3 на Java SE 10 JLS в этом случае. JLS утверждает, что « try
оператор -with-resources параметризован локальными переменными (известными как ресурсы ), которые инициализируются до выполнения try
блока и закрываются автоматически, в обратном порядке, из которого они были инициализированы, после выполнения try
блока».
JLS четко указывает, что несколько ресурсов могут быть определены в отношении одного try
оператора -with-resources, и определяет, как указано несколько ресурсов. В частности, это указывает, что за ним try
может следовать « ResourceSpecification », который состоит из « ResourceList », который состоит из одного или более « Resource ‘s». Когда существует более одного объявленного ресурса, несколько ресурсов разделяются точкой с запятой ( ;
). Эта спецификация нескольких ресурсов в списке, разделенном точкой с запятой, важна, поскольку любые ресурсы-кандидаты, не объявленные таким образом, не будут поддерживаться (не будут закрываться автоматически) оператором try
-with-resources.
Наиболее вероятным источником ошибок при указании нескольких ресурсов в операторе try
-with-resources является «вложение» экземпляров «ресурсов» вместо явного создания экземпляров локальных переменных каждой из них по отдельности с точками с запятой между каждой реализацией. Приведенные ниже примеры иллюстрируют разницу.
Два смешных, но иллюстративных занятия показаны далее. Каждый класс реализует AutoCloseable и может использоваться вместе с try
-with-resources, и его close()
метод будет вызываться автоматически при правильном использовании с try
оператором -with-resources. Они названы так, чтобы отражать, что OuterResource
экземпляр может быть создан с помощью экземпляра InnerResource
.
InnerResource.java
package dustin.examples.exceptions;
import static java.lang.System.out;
public class InnerResource implements AutoCloseable
{
public InnerResource()
{
out.println("InnerResource created.");
}
public InnerResource(
final RuntimeException exceptionToThrow)
{
throw exceptionToThrow != null
? exceptionToThrow
: new RuntimeException("InnerResource: No exception provided.");
}
@Override
public void close() throws Exception
{
out.println("InnerResource closed.");
}
@Override
public String toString()
{
return "InnerResource";
}
}
OuterResource.java
package dustin.examples.exceptions;
import static java.lang.System.out;
public class OuterResource implements AutoCloseable
{
private final InnerResource wrappedInnerResource;
public OuterResource(final InnerResource newInnerResource)
{
out.println("OuterResource created.");
wrappedInnerResource = newInnerResource;
}
public OuterResource(
final InnerResource newInnerResource,
final RuntimeException exceptionToThrow)
{
wrappedInnerResource = newInnerResource;
throw exceptionToThrow != null
? exceptionToThrow
: new RuntimeException("OuterResource: No exception provided.");
}
@Override
public void close() throws Exception
{
out.println("OuterResource closed.");
}
@Override
public String toString()
{
return "OuterResource";
}
}
Два определенных класса теперь можно использовать для демонстрации разницы между правильно объявленными экземплярами каждого в одном и том же try
операторе -with-resources в списке, разделенном точкой с запятой, и неправильно вложенным экземпляром внутреннего ресурса в конструкторе внешнего ресурса. Последний подход не работает так, как хотелось бы, потому что внутренний ресурс — без локальной переменной — не рассматривается как «ресурс» с точки зрения вызова его AutoCloseable.close()
метода.
Следующий листинг кода демонстрирует неправильный подход для создания экземпляров «ресурсов» в try
выражении -with-resources.
Неверный подход к использованию ресурсов в try
отчете -with-resources
try (OuterResource outer = new OuterResource(
new InnerResource(), new RuntimeException("OUTER")))
{
out.println(outer);
}
catch (Exception exception)
{
out.println("ERROR: " + exception);
}
Когда код, приведенный выше, выполняется, вывод « InnerResource created
» виден, но вывод, связанный с закрытием ресурса, не предоставляется. Это связано с тем, что экземпляр экземпляра InnerResource
был создан при вызове конструктора OuterResource
класса и никогда не назначался своей отдельной переменной в списке try
ресурсов оператора -with-resource. С реальным ресурсом это означает, что ресурс не закрыт должным образом.
Следующий листинг кода демонстрирует правильный подход для создания экземпляров «ресурсов» в try
выражении -with-resources.
Правильный подход к использованию ресурсов в try
отчете -with-resources
try(InnerResource inner = new InnerResource();
OuterResource outer = new OuterResource(inner, new RuntimeException("OUTER")))
{
out.println(outer);
}
catch (Exception exception)
{
out.println("ERROR: " + exception);
}
Когда приведенный выше код выполняется, выходные данные включают в себя и то InnerResource created
и другое InnerResource closed
, поскольку InnerResource
экземпляр был правильно назначен переменной в try
инструкции -with-resources. Следовательно, его close()
метод вызывается правильно, даже если во время его создания возникает исключение.
Заявление примерочных с-ресурсов раздел из Java Обучение включает в себя примеры правильного определения ресурсов в try
—with-ресурсов как определения индивидуального переменных разделенных точкой с запятой. Один пример демонстрирует этот правильный подход с java.util.zip.ZipFile и java.io.BufferedWriter . Другой пример демонстрирует этот правильный подход с экземплярами java.sql.Statement и java.sql.ResultSet .
Внедрение try
-with-resources в JDK 7 стало долгожданным дополнением к языку, благодаря которому разработчики Java упростили создание ресурсо-безопасных приложений, которые с меньшей вероятностью могут утекать или тратить ресурсы. Однако, когда несколько ресурсов объявляются в одном try
выражении -with-resources, важно обеспечить, чтобы каждый ресурс создавался индивидуально и назначался своей собственной переменной, объявленной в try
списке спецификаторов ресурса, чтобы гарантировать, что каждый ресурс правильно закрыт. , Быстрый способ проверить это состоит в том, чтобы убедиться, что для n AutoCloseable
реализуются ресурсы, указанные в разделе try.
Должно быть n-1 точка с запятой, разделяющих эти экземпляры ресурсов.