DZone
Java Zone
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
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Java Zone > Try-Catch-Resource and the Exception.getSuppressed() Method

Try-Catch-Resource and the Exception.getSuppressed() Method

Eyal Lupu user avatar by
Eyal Lupu
·
Mar. 18, 13 · Java Zone · Interview
Like (0)
Save
Tweet
7.96K Views

Join the DZone community and get the full member experience.

Join For Free

Java 7 is out there for such a long time now so this post is even not fashionably late but still there is one aspect of the try-with-resource construct which, in my opinion, is sometimes overlooked: In this post I would like to point out some behavioral change related to exception suppression which might affect code migrating from older Java versions.




Old Code

Let's assume the following pre-Java 7 code, for the example I assume a dummy OutputStream ('SampleStream') which throws IOWriteException when write() is invoked and IOCloseException when close() is invoked (both are faked exceptions derive from IOException). For the sake of the example both exceptions are always thrown - regardless of the state of the application/stream. Which exception would be thrown by the method below?

public void testTraditionalTryCatchWithExceptionOnFinally() throws IOException {
  OutputStream os = null;
  try {
    os = new SampleStream(); 
    os.write(0); // Throws IOWriteException 
  } finally {
    if (os != null) {
      os.close(); // Throws IOCloseException
  }
}

The invocation of os.write() throws IOWriteException which passed the control to the finally block. The os variable is not null so the os.close() method is invoked resulting in the IOCloseException. At that point the method execution ends throwing an instance of IOCloseException. A caller similar to the one below will print 'Failed to closed stream'.

try {
 testTraditionalTryCatchWithExceptionOnFinally();
} catch (IOWriteException e) {
 System.out.println("Failed to write to stream");
} catch (IOCloseException e) {
 System.out.println("Failed to close stream");
} catch (IOException e) {
 System.out.println("Error working with the stream");
}

Migrating to Try-catch-resource

The method above using a try with resource block would be written as

public void testJava7TryCatchWithExceptionOnFinally() throws IOException {
 try (OutputStream os = new SampleStream(true)) {
  os.write(0); // Throws IOWriteException
 }
}

Indeed more elegant and a very easy conversion of the code - however there is an important nuance from the caller point of view: the try-catch-resource version of the method throws IOWriteException rather than IOCloseException. Obviously the caller illustrated few paragraphs above will change its behavior when using the migrated version of the method. So what had seemed to be a naive internal method change becomes now a contract change.



What can be done: document and getSuppressed()

First thing is to be aware of that change - and to consider if this internal change in the method does worth it. If it is decided to do the change we should track down all usages of the modified method and to see if any changes need to be done. However in real life this is not always easy: in large projects or if the modified method is a part of a library provided to other projects (so there is no visibility  on who is using it) we should also include an explicit notification of that behavior change in the library documentation/release notes. Once the change is communicated with other developers they can use the getSuppressed() method to drill down into the different use cases. The try-catch-resource block does expose the suppressed exception using the new (since Java 1.7) getSuppressed() method. This method returns all of the suppressed exceptions by the try-catch-resource block (notice that it returns ALL of the suppressed exceptions if more than one occurred). A caller might use the following structure to reconcile with existing behavior

try { 
  testJava7TryCatchWithExceptionOnFinally(); // This is the method illustrated above
} catch (IOException e) {   
  Throwable[] suppressed = e.getSuppressed();
    for (Throwable t : suppressed) {
    // Check T's type and decide on action to be taken
  }
}

Not the most elegant solution I could think about - but still one of those things Java developers must be aware of.

And one last thing

Just another example on the importance of good unit test coverage which can promptly identify that kind of  'hidden changes'.

[some sample code for try-with-resource is at https://github.com/eyal-lupu/eyallupu-blog/tree/master/Java-SE/src/test/java/com/eyalllupu/blog/java7/trywithresource]
unit test Blocks Java (programming language) dev POST (HTTP) Library Execution (computing) Visibility (geometry) Drill

Published at DZone with permission of Eyal Lupu, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Top 20 Git Commands With Examples
  • Progressive Delivery With Argo Rollouts: Blue-Green Deployment
  • ETL/ELT on Kubernetes With Airbyte
  • Pub/Sub Design Pattern in .NET Distributed Cache

Comments

Java Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo