Одной из наиболее полезных новых функций Java 7 стало введение оператора try-with-resources [AKA Automatic Resource Management ( ARM )]. Привлекательность заявления « попробуй с ресурсами» заключается в его обещании «обеспечить закрытие каждого ресурса в конце заявления». «Ресурс» в этом контексте — это любой класс, который реализует AutoCloseable и его метод close () и создается в предложении «try» оператора try-with-resources .
 Спецификация языка Java [JLS] подробно описывает оператор try-with-resource в разделе 14.20.3 (в данном случае Java SE 10 JLS ).  JLS заявляет, что оператор try -with-resources параметризован локальными переменными (известными как ресурсы ), которые инициализируются до выполнения блока try и закрываются автоматически, в обратном порядке, из которого они были инициализированы, после выполнения try блок «. 
  В JLS четко указано, что для одного оператора try -with-resources можно определить несколько ресурсов, и указано, как указано несколько ресурсов.  В частности, это указывает, что за try может следовать « ResourceSpecification », которая состоит из « ResourceList », который состоит из одного или более « Resource ».  Если существует более одного объявленного ресурса, несколько ресурсов разделяются точкой с запятой ( ; ).  Эта спецификация нескольких ресурсов в списке, разделенном точкой с запятой, важна, поскольку любые ресурсы-кандидаты, не объявленные таким образом, не будут поддерживаться (не будут закрываться автоматически) оператором try -with-resources. 
  Наиболее вероятным источником ошибок при указании нескольких ресурсов в операторе try -with-resources является «вложение» экземпляров «ресурсов» вместо явного создания экземпляров локальных переменных каждой из них по отдельности с точками с запятой между каждой реализацией.  Следующие примеры иллюстрируют разницу. 
  Два смешных, но иллюстративных занятия показаны далее.  Каждый класс реализует AutoCloseable и поэтому может использоваться вместе с try -with-resources, и его метод close() вызываться автоматически при правильном использовании с оператором try -with-resources.  Они названы так, чтобы отражать, что OuterResource может быть создан с помощью экземпляра InnerResource . 
InnerResource.java
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
 | 
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
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
 | 
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 
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
try (OuterResource outer = new OuterResource(        new InnerResource(), new RuntimeException("OUTER"))){   out.println(outer);}catch (Exception exception){   out.println("ERROR: " + exception);} | 
  Когда приведенный выше код выполняется, вывод «InnerResource создан».  видно, но никакой информации, связанной с закрытием ресурса, не представлено.  Это связано с тем, что экземпляр InnerResource в вызове конструктора класса OuterResource и никогда не назначался своей отдельной переменной в списке ресурсов оператора try -with-resource.  С реальным ресурсом это означает, что ресурс не закрыт должным образом. 
  Следующий листинг кода демонстрирует правильный подход для создания экземпляров «ресурсов» в инструкции try -with-resources. 
  Правильный подход к использованию ресурсов в инструкции try -with resources 
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
try(InnerResource inner = new InnerResource();    OuterResource outer = new OuterResource(inner, new RuntimeException("OUTER"))){   out.println(outer);}catch (Exception exception){   out.println("ERROR: " + exception);} | 
  Когда код, приведенный выше, выполняется, вывод включает в себя оба «InnerResource создан».  И «Внутренний ресурс закрыт».  потому что экземпляр InnerResource был правильно назначен переменной в инструкции try -with-resources, и поэтому его метод close() вызывается правильно, даже когда во время его создания возникает исключение. 
  Раздел инструкции try-with-resources Учебников Java включает в себя несколько примеров правильного определения ресурсов в try -with-resources в виде разделенных точкой с запятой определений отдельных переменных.  Один пример демонстрирует этот правильный подход с 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 точка с запятой, разделяющая эти экземпляры ресурсов. 
|   Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG .  См. Оригинальную статью здесь: Тщательно укажите несколько ресурсов в одном заявлении о попытках использования ресурсов. 
 Мнения, высказанные участниками Java Code Geeks, являются их собственными.  |