DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions
  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService
  • A Maven Story
  • Java EE 6 Pet Catalog with GlassFish and MySQL

Trending

  • How to Build Real-Time BI Systems: Architecture, Code, and Best Practices
  • Monolith: The Good, The Bad and The Ugly
  • How Can Developers Drive Innovation by Combining IoT and AI?
  • AI-Driven Root Cause Analysis in SRE: Enhancing Incident Resolution
  1. DZone
  2. Coding
  3. Java
  4. How to Specify Multiple Resources in a Single Try-With-Resources Statement

How to Specify Multiple Resources in a Single Try-With-Resources Statement

The ability to specify multiple resources in a single try-with-resources statement is a feature introduced in Java 7. But, it can be fraught with peril if not used carefully. Read on to ensure you do this right every time.

By 
Dustin Marx user avatar
Dustin Marx
·
Aug. 27, 18 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
111.8K Views

Join the DZone community and get the full member experience.

Join For Free

One of the more useful features of Java 7 was the introduction of the try-with-resources statement, also known as the Automatic Resource Management (ARM). The attractiveness of the try-with-resources statement lies in its promise to "ensure that each resource is closed at the end of the statement." A "resource" in this context is any class that implements AutoCloseable and its close() method and is instantiated inside the "try" clause of the try-with-resources statement.

The Java Language Specification (JLS) describes the try-with-resources statement in detail in Section 14.20.3 of Java SE 10 JLS in this case. The JLS states that the " try-with-resources statement is parameterized with local variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block."

The JLS clearly specifies that multiple resources can be defined in relation to a single try-with-resources statement, and it specifies how multiple resources are specified. Specifically, it indicates that try can be followed by a " ResourceSpecification" that is composed of a " ResourceList" that is composed of one or more "Resource's." When there is more than a single declared resource, the multiple resources are delimited by a semicolon (;). This specification of multiple resources in a semicolon-delimited list is important because any candidate resources not declared in this manner will not be supported (will not be closed automatically) by the try-with-resources statement.

The most likely source of errors when specifying multiple resources in a try-with-resources statement is "nesting" instantiations of "resources," instead of explicitly instantiating local variables of each of them separately with semicolons between each instantiation. The examples below will illustrate the difference.

Two ridiculous but illustrative classes are shown next. Each class implements an AutoCloseable and can be used in conjunction with try-with-resources and will have its close() method called automatically when used correctly with the try-with-resources statement. They are named to reflect that the OuterResource can be instantiated with an instance of the 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";
   }
}


The two classes defined can now be used to demonstrate the difference between correctly declaring instances of each in the same try-with-resources statement in a semicolon-delimited list and incorrectly nesting instantiation of the inner resource within the constructor of the outer resource. The latter approach doesn't work as well as hoped, because the inner resource  —without a locally defined variable — is not treated as a "resource" in terms of invoking its AutoCloseable.close() method.

The next code listing demonstrates the incorrect approach for instantiating "resources" in the try-with-resources statement.

Incorrect Approach for Instantiating Resources in try-with-resources Statement

try (OuterResource outer = new OuterResource(
        new InnerResource(), new RuntimeException("OUTER")))
{
   out.println(outer);
}
catch (Exception exception)
{
   out.println("ERROR: " + exception);
}


When the code above is executed, the output " InnerResource created" is seen, but no output is ever presented related to the resource's closure. This is because the instance of InnerResource was instantiated within the call to the constructor of the OuterResource class and was never assigned to its own separate variable in the resource list of the try-with-resource statement. With a real resource, the implication of this is that the resource is not closed properly.

The next code listing demonstrates the correct approach for instantiating "resources" in the try-with-resources statement.

Correct Approach for Instantiating Resources in try-with-resources Statement

try(InnerResource inner = new InnerResource();
    OuterResource outer = new OuterResource(inner, new RuntimeException("OUTER")))
{
   out.println(outer);
}
catch (Exception exception)
{
   out.println("ERROR: " + exception);
}


When the code above is executed, the output includes both InnerResource created and InnerResource closed , because the InnerResource instance was properly assigned to a variable within the try-with-resources statement. Therefore, its close() method is properly called, even when an exception occurs during its instantiation.

The try-with-resources statement section of the Java Tutorials includes examples of correctly specifying the resources in the try-with-resources as semicolon-delimited individual variable definitions. One example shows this correct approach with java.util.zip.ZipFile and java.io.BufferedWriter. Another example shows this correct approach with instances of java.sql.Statement and java.sql.ResultSet.

The introduction of try-with-resources in JDK 7 was a welcome addition to the language that it made it easier for Java developers to write resource-safe applications that were not as likely to leak or waste resources. However, when multiple resources are declared within a single try-with-resources statement, it's important to ensure that each resource is individually instantiated and assigned to its own variable declared within the try's resource specifier list to ensure that each and every resource is properly closed. A quick way to check this is to ensure that for n, AutoCloseable is implementing resources specified in the try.There should be n-1 semicolons, separating those instantiated resources.

Java (programming language) Listing (computer) Java language Execution (computing) application Java Development Kit Blocks IT

Published at DZone with permission of Dustin Marx, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Five Java Developer Must-Haves for Ultra-Fast Startup Solutions
  • Mastering Concurrency: An In-Depth Guide to Java's ExecutorService
  • A Maven Story
  • Java EE 6 Pet Catalog with GlassFish and MySQL

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!