Одной из наиболее полезных новых функций 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, являются их собственными. |