Monday, April 30, 2012

Specifying Appropriate NetBeans JDK Source Release

NetBeans uses its projects' settings for javac.source (and javac.target) in more ways than simply enforcing javac's use of the -source and -target. In this post, I look at some of the numerous benefits of appropriately setting the Java release source level in NetBeans.

In a standard ("Java Application") NetBeans project, the JDK version is for the project is specified in the Project -> Properties -> Sources window. This is shown in the next screen snapshot with a really old version (1.2) of the SDK displayed.

Setting a project like that shown in the above screen snapshot leads to the setting of the properties javac.source and javac.target in the nbprojects/project.properties file. This is shown in the next screen snapshot.

There are several benefits to setting this JDK/Java version source level appropriately. According to the JDK 7 javac compiler documentation, it respects the following releases: 1.3, 1.4, 1.5 (5), 1.6 (6), and 1.7 (7). NetBeans 7.1 lists even more versions, ranging from JDK 1.2 through JDK 7.

Some benefits of setting the source level appropriately in NetBeans are obvious. For example, if the source JDK release is not set to at least 1.5 (or 5), then standard language constructs such as annotations, enums, and generics are shown are compilation errors in NetBeans. An example of this is shown in the next screen snapshot, which depicts the NetBeans error message when an enum is specified in a NetBeans project in which the JDK release is specified as 1.4.

The last example showed how using an "older" release can lead to errors regarding language features that did not exist for that release. An opposite benefit of this can be achieved by moving NetBeans's project's release to the new SDK release when appropriate because it can help developers identify ways in which they can improve their code base with the new version. I specifically discussed this approach using NetBeans 7 to "modernize" Java code bases to newer releases of Java in the blog post Seven NetBeans Hints for Modernizing Java Code. In that post, I demonstrated how NetBeans 7 (and even some older versions of NetBeans) can help flag areas of code where J2SE 5 and Java SE 7 new features apply and are not being used.

It's easy to think that there is no use in setting the source release in NetBeans to 1.6 (6) because Java SE 6 did not introduce any new language features. However, it turns out that there still are some differences and it's probably best to have 1.6 specified if that's the JDK the software is being written against. In the blog post Differences between source level 1.5 and 1.6 in NetBeans, Antonio Santiago wrote in early 2008 that NetBeans made use of Java SE 6's new Swing-related classes when JDK 1.6 was set as the release. This is preferable to using third-party libraries.

The use of new Java SE 6 SDK classes is not the only reason to have NetBeans projects configured to 1.6 if that's the version you're deploying against. Another difference between J2SE 5 and Java SE 6 treatment is the use of the @Override annotation on methods of classes that implement an interface. With NetBeans configured for J2SE 5, only methods extending a parent had a hint for @Override suggested, but in NetBeans configured to use Java SE 6 as the source release, methods implementing an interface also enjoy the hint to use that annotation. Note that if the source release is not set to at least 1.5, methods generated by NetBeans to implement an interface are generated without any @Override annotation in either case. The @Override annotation can be used on methods implementing an interface in NetBeans when JDK 1.5 is specified, but the issue is that there is no warning to add that annotation when not specified unless in at least JDK 1.6.

The difference in treatment of @Override has not been exclusive to NetBeans. The Javadoc for the Overrides annotation differs significantly between 1.5 and 1.7 (but interestingly not between 1.5 and 1.6):

1.5/1.6 Javadoc Description for Override
Indicates that a method declaration is intended to override a method declaration in a superclass. If a method is annotated with this annotation type but does not override a superclass method, compilers are required to generate an error message.
1.7 Javadoc Description for Override
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type compilers are required to generate an error message unless at least one of the following conditions hold:< br/>
  • The method does override or implement a method declared in a supertype.
  • The method has a signature that is override-equivalent to that of any public method declared in Object.

Section 9.6.3.4 of the Java SE 7 Java Language Specification states, "This behavior differs from that in Java SE 5.0, where @Override caused a compile-time error if applied to a method that implemented a method from a superinterface that was not also present in a superclass." More details regarding @Override in J2SE 5 versus Java SE 6 are available here.

Returning from the side note on @Override, one of my favorite additions to Java SE 7 is not even a language feature. The new Objects class is especially handy for writing more standard and safer implementations of the "common" methods equals(Object) and hashCode(). If a developer has his or her NetBeans project configured to use JDK 1.7 as the release, NetBeans takes advantage of the Objects class to implement these methods.

I have looked at some of the benefits NetBeans provides for recent versions of the JDK (1.5, 1.6, and 1.7), but I am sure there are more that I'm not aware of. The point of all this is that it is best to ensure that a particular project is configured to be using the correct source version even if it is believed that the version difference does not matter. It may not matter outside of NetBeans (such as to javac) in some cases, but it likely does matter to NetBeans.

Monday, April 23, 2012

Improving On assertEquals with JUnit and Hamcrest

In my blog post Are Static Imports Becoming Increasingly Accepted in Java?, I discussed the increasing use of static imports in Java to make code more fluent in certain contexts. Unit testing in Java has been particularly affected by the static import and in this blog post I provide one quick example of using static imports to make more fluent unit tests that use JUnit and Hamcrest.

The next code listing is a simple IntegerArithmetic class that has one method that needs to be unit tested.

IntegerArithmetic.java
package dustin.examples;

/**
 * Simple class supporting integer arithmetic.
 * 
 * @author Dustin
 */
public class IntegerArithmetic
{
   /**
    * Provide the product of the provided integers.
    * 
    * @param integers Integers to be multiplied together for a product.
    * @return Product of the provided integers.
    * @throws ArithmeticException Thrown in my product is too small or too large
    *     to be properly represented by a Java integer.
    */
   public int multiplyIntegers(final int ... integers)
   {
      int returnInt = 1;
      for (final int integer : integers)
      {
         returnInt *= integer;
      }
      return returnInt;
   }
}

A common approach for testing one aspect of the above method is shown next.

   /**
    * Test of multipleIntegers method, of class IntegerArithmetic, using standard
    * JUnit assertEquals.
    */
   @Test
   public void testMultipleIntegersWithDefaultJUnitAssertEquals()
   {
      final int[] integers = {2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
      final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;
      final int result = this.instance.multiplyIntegers(integers);
      assertEquals(expectedResult, result);
   }

In the fairly typical unit test example shown above, JUnit's assertEquals is called in a fluent fashion because of the static import of org.junit.Assert.* (not shown). However, recent versions of JUnit (JUnit 4.4+) have begun including Hamcrest core matchers and this allows for an even more fluent test as depicted in the next code snippet.

   /**
    * Test of multipleIntegers method, of class IntegerArithmetic, using core
    * Hamcrest matchers included with JUnit 4.x.
    */
   @Test
   public void testMultipleIntegersWithJUnitHamcrestIs()
   {
      final int[] integers = {2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
      final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;
      final int result = this.instance.multiplyIntegers(integers);
      assertThat(result, is(expectedResult));
   }

In this example, JUnit's assertThat (also available as part of the static import of org.junit.Assert.* since JUnit 4.4) is used in conjunction with the included Hamcrest core matcher is(). It's certainly a matter of taste, but I prefer this second approach as more readable to me. Asserting that something (the result) is something else (the expected) seems more readable and more fluent than the older approach. It can sometimes be tricky to remember whether to list the expected or actual result first when using assertEquals and the combination of assertThat and is() makes for a little less work when I write and read tests. Even a little less work, especially when multiplied by numerous tests, is welcome.

Saturday, April 14, 2012

Deleting All .class Files with Groovy

When running simple Java tests either to learn how something works in Java or to build examples for my blog posts, I often store the examples in the same directory on my machine. I decided that I wanted to remove all the generated .class files from this directory. There are several approaches to doing this on a Linux machine, but I wanted to remove these files on a Windows machine. I know there are tools and ways to do this on Windows, but I knew it would take me less time to write a simple Groovy script to do it than to search online for such a tool. This post provides and briefly describes the simple Groovy script for removing .class files.

deleteClassFiles.groovy
#!/usr/bin/env groovy
if (args.length < 1)
{
   println "Please specify directory under which .class files should be removed"
   println "  (including .class files in sub-directories)."
   System.exit(-1)
}

def directoryName = args[0]
println "Remove .class files in ${directoryName} and its subdirectories..."
def directory = new File(directoryName)
def classPattern = ~/.*\.class/
directory.eachFileRecurse(groovy.io.FileType.FILES)
{ file ->
   if (file ==~ classPattern)
   {
      println "Deleting ${file}..."
      file.delete()
   }
}

The above script will remove all files that have names ending with a .class suffix in the provided directory or any of its sub-directories. The directory is specified via a single command-line argument to the script, so I did not use Groovy's built-in CLI support in this case. The script instead relies on Groovy's implicit availability of the args parameter representing the command line arguments.

The Groovy script featured in this post takes advantage of the Groovy GDK File extension's eachFileRecurse method to recursively iterate through the names of the files in the provided directory and its subdirectories. Another convenient Groovy feature employed in this script is application of Groovy regular expression support to specify the pattern (file names ending with ".class" extension) and then to use the pattern matcher in the conditional that decides which files are to be deleted.

The above script prints out the files to be deleted as it deletes them. One could easily enhance the script to accept a parameter that would display files that would be deleted without actually deleting them. For me, this script was more proof that Groovy is so easy to use that sometimes it's easier to write a new script in Groovy to accomplish daily tasks than it is to find existing tools and scripts online to download.

Wednesday, April 11, 2012

Are Static Imports Becoming Increasingly Accepted in Java?

There was a time when the use of the word ain't was widely considered unacceptable, at least in polite society. Indeed, at that time (and perhaps still today), many people did (and do) not consider ain't to be a real word. Although the word ain't remains controversial and its usage is still often considered improper, it seems to be slowly gaining general acceptance and holding its own in terms of frequency of use. At one time, it was used intentionally for emphasis by "people who know better," but seems to be slowly gaining in terms of popularity. In many ways, the static import introduced with J2SE 5 seems to be treated similarly to use of the word ain't.

The J2SE 5 Programming Language Guide's section on Static Imports is famously quoted (emphasis is part of original): "So when should you use static import? Very sparingly!" The section's final paragraph describes when static import might be preferable:

So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from. Importing all of the static members from a class can be particularly harmful to readability; if you need only one or two members, import them individually. Used appropriately, static import can make your program more readable, by removing the boilerplate of repetition of class names.

Like the word "ain't," the educated Java developer masses seem to be almost universally in agreement that the static import should be used sparingly. The reasoning here is obvious. First, the official documentation says so. Second, and far more importantly, there is no question that overuse of static import might actually lead to less readable code even if it's more concise code. In fact, too much static importing might lead to collisions that will remove the ability to use static imports so much. Despite awareness and acknowledgement of the evils and potential abuses of the static import, its use seems to be growing in the Java community.

When writing simple examples to illustrate points (such as for posts on this blog), I frequently don't bother using a logging framework and instead resort to simple use of System.out and System.err. I don't mind making the assumption that any reference to out in my code refers to the handle to the standard output and that any reference to err refers to the handle to the standard error. I don't plan to use out or err in any other context, so this brings conciseness to the simple code without loss of readability or adding of ambiguity. It also feels very much like Groovy's approach (although not quite as concise as that) to writing to standard output. You can find more details on this approach in Java static import: System.out and err, in my post Static Imports and System.out, and in Cay Horstmann's post Are you using static import?

Perhaps even more prevalent use of static import in the Java world occurs in the name of unit testing. Several of the most popular Java-oriented unit testing frameworks encourage use of static imports for more fluent test code. JUnit's Assert methods, Mockito's Mockito methods, and Hamcrest's Matchers are some of the most obvious examples of the prevalence of static import usage in the Java unit testing world.

In the post My dislike of Java’s static import, Mark Needham described a situation I think many Java development shops find themselves in when it comes to static imports:

On my last project we ended up saying that import static was allowed in test code because there were relatively few places the static methods could be imported from, but when it came to production code the fully qualified path was required.

Even use of static imports in test code is not without issue or controversy. The StackOverflow thread Finding import static statements for Mockito constructs talks about some frustrations related to the use of static imports. Needham also addressed this issue:

The benefit of this approach is that it makes the code read more fluently but the disadvantage is that you can’t immediately tell where a method lives. I want to be able to tell what is going on in the code from looking at it and anything which prevents this is a hindrance.

So far, I've looked at use of Java static imports in association with calls to java.lang.System.out and in association with unit testing. Both of these cases are not typical production code cases (logging with a logging framework is preferable in production to standard output and unit tests are not production code, though they may be delivered with it).

It is perhaps less obvious which Java frameworks intended for production code encourage use of static imports. One example is lambdaj. The lambdaj features Wiki page starts off by recommending use of static imports:

All those features are provided as static methods in the class Lambda, so the best way to use them is just to add the following import:

import static ch.lambdaj.Lambda.*;

in the classes where you want to use it.

The more general use case for Java use of static import is the development of Domain-Specific Languages (DSLs) in Java. In many ways, the use of static imports already discussed in this post for JUnit, Mockito, Hamcrest, and Lambdaj are specific examples of this more general trend toward fluent interfaces and DSLs.

For good reason, I believe that most Java developers are cautious about overuse and abuse of static imports. However, increased use of static imports in appropriate circumstances seems to be the result of playing with these and learning the positives and negatives of them. The rise of the JVM scripting languages and other more concise (less ceremony) languages has also probably affected the general thinking about use of static imports.

The drive for fluent interfaces (positive effect of static imports) must be compared to the maintenance and readability costs associated with use of static imports. In general, just as I think "ain't" is still generally frowned upon but is perhaps less frowned upon than it used to be, I also think that static imports are still generally discouraged, but that perhaps we as a Java community have started to see situations in which they might be okay or even a positive feature worth their cost. I don't think anyone thinks it's a good idea to use them frequently and without regard to the context in which they are being used.

Monday, April 2, 2012

Java 7's Support for Suppressed Exceptions

A new constructor and two new methods were added to the Throwable class (parent of Exception and Error classes) in JDK 7. The new constructor and two new methods were added to support "suppressed exceptions" (not to be confused with the bad practice of swallowing or ignoring exceptions). In this post, I look at why these methods were introduced and how they are used in JDK 7. I throw in a short discussion on how suppressed exceptions are different than chained exceptions.

Suppressed exceptions play a significant role in the execution of the new-to-Java 7 try-with-resources statement (also known as Automatic Resource Management [ARM]). Providing API support for this new resource management capability appears to have been the primary driver for the new constructor and methods on the Throwable class that provide access to suppressed exceptions, but the APIs support suppressed exceptions being used outside of the try-with-resources statement.

Perhaps the most common use case for encountering suppressed exceptions is when a try-with-resources statement (which is the one type of try that does not require a catch or finally clause according to Java Language Specification Java SE 7 Edition Section 14.20) encounters an exception within the try block and then encounters another exception in implicitly trying to close the related resource.

To illustrate this case, I make up my own "resource" that can be used in a try-with-resource statement because it implements the java.lang.AutoCloseable interface. This "naughty resource" intentionally throws an exception when the code using it attempts to use it and then continues its bad form by throwing another exception when the overridden close method (the only one prescribed by the AutoCloseable interface) is called. The code listing for NaughtyResource is shown next.

NaughtyResource.java
package dustin.examples;

/**
 * Resource that throws exceptions both in its use and its closure and is only
 * intended for use in demonstrating Java 7's suppressed exceptions APIs. This
 * is not a well-behaved class.
 * 
 * @author Dustin
 */
public class NaughtyResource implements AutoCloseable
{
   /**
    * Method that intentionally throws an exception.
    * 
    * @throws RuntimeException Thrown no matter how you call me.
    */
   public void doNothingGood()
   {
      throw new RuntimeException("Nothing good can come of this.");
   }

   /**
    * The overridden closure method from AutoCloseable interface.
    * 
    * @throws Exception Exception that might be thrown during closure of this
    *    resource.
    */
   @Override
   public void close() throws Exception
   {
      throw new UnsupportedOperationException("Not supported yet.");
   }
}

With a naughty resource now available, it's time to use the naughty resource and demonstrate the suppressed exceptions API. The next image depicts what happens if one tries to use this resource without catching the Exception thrown implicitly by the close method and without declaring the method as throwing it.

This is an error message provided by javac as shown in the next screen snapshot.

I have shown the two previous screen snapshots to emphasize the implicit call to close that is performed on the resource. The error message shown in the NetBeans editor and in the console clearly states this is the case.

The next code listing contains the first version of the SuppressedExceptions class that compiles.

SuppressedExceptions.java (Version 1)
package dustin.examples;

/**
 * Demonstrate JDK 7's Suppressed Exceptions API support.
 * 
 * @author Dustin
 */
public class SuppressedExceptions
{
   /**
    * Executable function demonstrating suppressed exceptions.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments) throws Exception
   {
      try (NaughtyResource naughty = new NaughtyResource())
      {
         naughty.doNothingGood();
      }
   }
}

Although two exceptions are really encountered when the above code is executed (one from within the try block on the call to NaughtyResource.doNothingGood() and one on the implicitly called close method), only one percolates to the top and is shown when the application is run. This is demonstrated in the next screen snapshot.

As the last image proves, only the exception encountered in try try block of the try-with-resources statement is shown. This is where the ability to ask a Throwable (in this case an Exception) about its suppressed exceptions comes in handy. To demonstrate this, version 2 of the SuppressedExceptions class (which uses Throwable.getSuppressed()) is shown next.

SuppressedExceptions.java (Version 2)
package dustin.examples;

import static java.lang.System.err;

/**
 * Demonstrate JDK 7's Suppressed Exceptions API support.
 * 
 * @author Dustin
 */
public class SuppressedExceptions
{
   /**
    * Method that uses NaughtyResource with try-with-resource statement.
    * 
    * @throws Exception Expected exception for try-with-resource used on the
    *    NaughtyResource.
    */
   public static void performTryWithResource() throws Exception
   {
      try (NaughtyResource naughty = new NaughtyResource())
      {
         naughty.doNothingGood();
      }  
   }

   /**
    * Executable function demonstrating suppressed exceptions.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      try
      {
         performTryWithResource();
      }
      catch (Exception ex)
      {
         err.println("Exception encountered: " + ex.toString());
         final Throwable[] suppressedExceptions = ex.getSuppressed();
         final int numSuppressed = suppressedExceptions.length;
         if (numSuppressed > 0)
         {
            err.println("\tThere are " + numSuppressed + " suppressed exceptions:");
            for (final Throwable exception : suppressedExceptions)
            {
               err.println("\t\t" + exception.toString());
            }
         }
      }
   }
}

The above application will print out any suppressed exceptions. In this case, the exception encountered upon attempted closure of NaughtyResource is now shown as one of the suppressed exceptions. This is demonstrated in the next screen snapshot.

As documented in the Java Tutorial, we see that the only thrown exception is the exception encountered within the try block of the try-with-resources statement and the second exception encountered during resource closure is "suppressed" (but still associated and available from the actually thrown exception).

One doesn't need to use try-with-resources to work with suppressed exceptions. The next code listing adapts SuppressedExceptions to use a more traditional try-finally.

SuppressedExceptions.java (Version 3)
package dustin.examples;

import static java.lang.System.err;

/**
 * Demonstrate JDK 7's Suppressed Exceptions API support.
 * 
 * @author Dustin
 */
public class SuppressedExceptions
{
   /**
    * Method that uses NaughtyResource with JDK 7 try-with-resource statement.
    * 
    * @throws Exception Expected exception for try-with-resource used on the
    *    NaughtyResource.
    */
   public static void performTryWithResource() throws Exception
   {
      try (NaughtyResource naughty = new NaughtyResource())
      {
         naughty.doNothingGood();
      }  
   }

   /**
    * Method that uses NaughtyResource with traditional try-finally statement.
    * 
    * @throws Exception Exception thrown during use of NaughtyResource.
    */
   public static void performTryFinally() throws Exception
   {
      final NaughtyResource naughty = new NaughtyResource();
      try
      {
         naughty.doNothingGood();
      }
      finally
      {
         naughty.close();
      }
   }

   /**
    * Executable function demonstrating suppressed exceptions.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      try
      {
//         performTryWithResource();
         performTryFinally();
      }
      catch (Exception ex)
      {
         err.println("Exception encountered: " + ex.toString());
         final Throwable[] suppressedExceptions = ex.getSuppressed();
         final int numSuppressed = suppressedExceptions.length;
         if (numSuppressed > 0)
         {
            err.println("\tThere are " + numSuppressed + " suppressed exceptions:");
            for (final Throwable exception : suppressedExceptions)
            {
               err.println("\t\t" + exception.toString());
            }
         }
         else
         {
            err.println("\tNo Suppressed Exceptions.");
         }
      }
   }
}

The above code calls a method that uses try-finally and the behavior is different than that for the try-with-resources example as shown in the next screen snapshot.

The try-finally shows the exception encountered on attempted resource closure rather than the exception encountered in use of the resource (opposite of try-with-resources shown above). An additional difference is that the other exception is not available even as a suppressed exception in the try-finally case. This is an example of the well-advertised "lost exception" issue of a potentially "trivial" exception (closing the resource) hiding a potentially more significant exception (actually using the resource).

If I want to see both exceptions thrown during use and closure of NaughtyResource in conjunction with try-finally, I can make use of Throwable.addSuppressed(Throwable) as shown in the next code listing. In that listing, the try and finally clauses are enhanced to capture the exception thrown during use of the NaughtyResource and to add that caught exception to the actually-thrown exception as a suppressed exception.

SuppressedExceptions.java (Version 4)
package dustin.examples;

import static java.lang.System.err;

/**
 * Demonstrate JDK 7's Suppressed Exceptions API support.
 * 
 * @author Dustin
 */
public class SuppressedExceptions
{
   /**
    * Method that uses NaughtyResource with JDK 7 try-with-resource statement.
    * 
    * @throws Exception Expected exception for try-with-resource used on the
    *    NaughtyResource.
    */
   public static void performTryWithResource() throws Exception
   {
      try (NaughtyResource naughty = new NaughtyResource())
      {
         naughty.doNothingGood();
      }  
   }

   /**
    * Method that uses NaughtyResource with traditional try-finally statement.
    * 
    * @throws Exception Exception thrown during use of NaughtyResource.
    */
   public static void performTryFinally() throws Exception
   {
      final NaughtyResource naughty = new NaughtyResource();
      Throwable throwable = null;
      try
      {
         naughty.doNothingGood();
      }
      catch (Exception usingEx)
      {
         throwable = usingEx;
      }
      finally
      {
         try
         {
            naughty.close();
         }
         catch (Exception closingEx)
         {
            if (throwable != null)
            {
               closingEx.addSuppressed(throwable);
               throw closingEx;
            }
         }
      }
   }

   /**
    * Executable function demonstrating suppressed exceptions.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      try
      {
//         performTryWithResource();
         performTryFinally();
      }
      catch (Exception ex)
      {
         err.println("Exception encountered: " + ex.toString());
         final Throwable[] suppressedExceptions = ex.getSuppressed();
         final int numSuppressed = suppressedExceptions.length;
         if (numSuppressed > 0)
         {
            err.println("\tThere are " + numSuppressed + " suppressed exceptions:");
            for (final Throwable exception : suppressedExceptions)
            {
               err.println("\t\t" + exception.toString());
            }
         }
         else
         {
            err.println("\tNo Suppressed Exceptions.");
         }
      }
   }
}

The output of the modified class is shown next. Note that the exception resulting from using the resource itself is now associated with the thrown exception as a suppressed exception. Although not shown here, Throwable also now provides a constructor that allows specification via boolean argument of whether suppressed exceptions are allowed (enabled) or not allowed (disallowed) for the newly instantiated Throwable.

Another perspective from which to look at suppressed exceptions is that of full stack traces. The following three images are screen snapshots of full stack traces resulting from use of try-with-resources (explicitly shows suppresed exception), use of traditional try-finally statement without explicitly adding suppressed exceptions (and so no suppressed exceptions in full stack trace), and use of traditional try-finally with suppressed exceptions explicitly added (and thus do appear in full stack trace). I've added a red line to each image to separate show where the full stack trace ends and have circled the explicit reference to the suppressed exception where applicable.

Suppressed Exceptions Versus Chained Exceptions

Suppressed exceptions are not the same as chained exceptions. Chained exceptions were introduced with JDK 1.4 and were intended to make it possible to easily track causal relationships between exceptions. Typically, chained exceptions resulted from associating a newly thrown exception with the exception that was caught and caused the throwing of a new exception. For example, an unchecked exception might be thrown that "wraps" a checked exception that was caught and they could be chained together.

Suppressed exceptions were introduced with JDK 7 and are less about causal relationships and more about representing possibly related but not necessarily causal multiple exceptional conditions in a single thrown exception. In my naughty resource example above, the naughty resource's exception upon its sole method being called was NOT the cause of it thrown an exception upon invocation of its close method. Because of this, it makes more sense for the two exceptions to be associated (via the suppressed exception mechanism) than to force one to appear to be the cause of the other in a chained relationship.

It may be easiest to quickly understand the difference between chained exceptions and suppressed exceptions by comparing Throwable's methods for accessing each type. For chained exceptions, one invokes a particular Exception's (Throwable's) method. This method returns a single instance of the causing Throwable. That returned Throwable can be asked for its cause and the process is repeated up the chain of causing Throwables. The important observation is that each given Throwable has a single causing Throwable. This can be contrasted with the ability of a Throwable to provide multiple suppressed Throwables (in an array) when its getSuppressed() method is called.

NetBeans Recommends try-with-resource

It's worth noting here that NetBeans warns about the use of try-finally and suggests replacing it with try-with-resources as discussed in my post Seven NetBeans Hints for Modernizing Java Code and in the screen snapshot shown next.

Conclusion

I believe it's obvious why NetBeans recommends that the developer change a try-finally for resource handling to a try-with-resources statement. It is often preferable to know first what operation on the resource caused an exception, but it is nice to be able to access the exception on closure as well if desired. If I had to choose, I'd typically be more interested in the resource's problem during execution because the closure problem might be a derivative of that. However, having both is even better. The traditional try-finally only lists the exception upon closure without additional effort to relay both. The try-with-resource statement is not only more concise; it's also more useful thanks to its built-in support for inclusion of suppressed exceptions.

JDK 7 Additions to Currency Class

The java.util.Currency class has been available since JDK 1.4, but JDK 7 has provided some useful new methods at the class and instance level. I look at these new methods in this post.

The Currency class represents worldwide currencies as "identified by their ISO 4217 currency codes" available at the International Organization for Standardization site. Although one can override the represented currencies available in an instance of the JVM by placing an appropriate properties file in <JAVA_HOME>/lib/currency.properties, most of us are likely to use the currencies provided out-of-the-box with the JVM. It is easy to find out what these available currencies are with the new-to-JDK 7 class-level (static) function getAvailableCurrencies().

I like it when the JDK provides access to runtime JVM-specific details. The addition of Currency.getAvailableCurrencies() brings this support to Currency similar to what is available for locales [Locale.getAvailableLocales()], time zones [TimeZone.getAvailableIDs()], characters sets [CharSet.availableCharsets()], and available JVM scripting engines [ScriptEngineManager.getEngineFactories()]. It is easy to invoke the static function with a single line Groovy script called directly with the -e option:

groovy -e "Currency.availableCurrencies.each{println it}"

There are three new instance-level methods added to Currency in JDK 7. Two of them [getDisplayName() and getDisplayName(Locale)] provide a String-based name of the currency instance (one for default locale and one for a provided locale). The third new method [getNumericCode()] provides an int representing the numeric code for that currency instance.

The next code listing is of a simple Java application that runs through all available currencies using the method added to JDK 7 and then prints the numeric code for each currency along with the two versions of the currency display name as provided by new JDK 7 methods.

Example Demonstrating JDK 7 Methods on Currency
package dustin.examples;

import static java.lang.System.out;
import java.util.Currency;
import java.util.Locale;
import java.util.Set;

/**
 * Demonstrate methods added to java.util.Currency in JDK 7.
 * 
 * @author Dustin
 */
public class Main
{
   /**
    * Main executable function for demonstrating Currency methods added in JDK 7.
    * 
    * @param arguments The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      final Set<Currency> currencies = Currency.getAvailableCurrencies();
      for (final Currency currency : currencies)
      {
         out.println(
              "Currency: "
            + currency.getDisplayName() + "/"
            + currency.getDisplayName(Locale.ITALIAN) + "/"
            + currency.getNumericCode());
      }
   }
}

When the above is executed on the JVM I'm using, the output appears as follows:

Currency: Venezuelan Bolívar/Bolívar venezuelano forte/937
Currency: Colombian Peso/Peso Colombiano/170
Currency: French Franc/Franco Francese/250
Currency: Kyrgystani Som/Som Kirghiso/417
Currency: Euro/Euro/978
Currency: Maltese Lira/Lira Maltese/470
Currency: Georgian Lari/Lari Georgiano/981
Currency: Afghan Afghani (1927-2002)/Afgani (1927-2002)/4
Currency: US Dollar (Next day)/Dollaro Statunitense (Next day)/997
Currency: Mozambican Metical/Metical del Mozambico/943
Currency: Dutch Guilder/Fiorino Olandese/528
Currency: Panamanian Balboa/Balboa di Panama/590
Currency: Qatari Rial/Rial del Qatar/634
Currency: Bahamian Dollar/Dollaro delle Bahamas/44
Currency: Djiboutian Franc/Franco Gibutiano/262
Currency: Serbian Dinar (2002-2006)/Serbian Dinar (2002-2006)/891
Currency: New Zealand Dollar/Dollaro Neozelandese/554
Currency: Syrian Pound/Sterlina Siriana/760
Currency: Malagasy Franc/Franco Malgascio/450
Currency: Venezuelan Bolívar (1871-2008)/Bolivar Venezuelano/862
Currency: Saudi Riyal/Ryal Saudita/682
Currency: Rwandan Franc/Franco Ruandese/646
Currency: Yemeni Rial/Rial dello Yemen/886
Currency: Barbadian Dollar/Dollaro di Barbados/52
Currency: Sierra Leonean Leone/Leone della Sierra Leone/694
Currency: Sri Lankan Rupee/Rupia di Sri Lanka/144
Currency: Chilean Peso/Peso Cileno/152
Currency: Bermudan Dollar/Dollaro delle Bermuda/60
Currency: Omani Rial/Rial Omanita/512
Currency: Myanma Kyat/Kyat di Myanmar/104
Currency: Gambian Dalasi/Dalasi del Gambia/270
Currency: Guatemalan Quetzal/Quetzal Guatemalteco/320
Currency: CFP Franc/Franco CFP/953
Currency: Turkmenistani Manat (1993-2009)/Manat Turkmeno/795
Currency: Romanian Leu/Romanian Leu/946
Currency: Singapore Dollar/Dollaro di Singapore/702
Currency: Jamaican Dollar/Dollaro Giamaicano/388
Currency: Bolivian Boliviano/Boliviano/68
Currency: Eritrean Nakfa/Nakfa Eritreo/232
Currency: Turkmenistani Manat/Turkmenistani Manat/934
Currency: Mongolian Tugrik/Tugrik Mongolo/496
Currency: Indonesian Rupiah/Rupia Indonesiana/360
Currency: ZWN/ZWN/942
Currency: Luxembourgian Franc/Franco del Lussemburgo/442
Currency: Russian Ruble (1991-1998)/Rublo della CSI/810
Currency: São Tomé and Príncipe Dobra/Dobra di Sao Tomé e Principe/678
Currency: Ukrainian Hryvnia/Hrivna Ucraina/980
Currency: Argentine Peso/Peso Argentino/32
Currency: Bahraini Dinar/Dinaro del Bahraini/48
Currency: Belize Dollar/Dollaro Belize/84
Currency: Russian Ruble/Rublo Russo/643
Currency: Laotian Kip/Kip Laotiano/418
Currency: Maldivian Rufiyaa/Rufiyaa delle Maldive/462
Currency: Libyan Dinar/Dinaro Libico/434
Currency: Sudanese Dinar (1992-2007)/Dinaro Sudanese/736
Currency: Danish Krone/Corona Danese/208
Currency: Zimbabwean Dollar (2008)/Zimbabwean Dollar (2008)/935
Currency: Spanish Peseta/Peseta Spagnola/724
Currency: Macanese Pataca/Pataca di Macao/446
Currency: Surinamese Guilder/Fiorino del Suriname/740
Currency: Samoan Tala/Tala della Samoa Occidentale/882
Currency: Swazi Lilangeni/Lilangeni dello Swaziland/748
Currency: Tanzanian Shilling/Scellino della Tanzania/834
Currency: Portuguese Escudo/Escudo Portoghese/620
Currency: XUA/XUA/965
Currency: Armenian Dram/Dram Armeno/51
Currency: Greek Drachma/Dracma Greca/300
Currency: Guinean Franc/Franco della Guinea/324
Currency: Nicaraguan Córdoba/Córdoba oro nicaraguense/558
Currency: Gibraltar Pound/Sterlina di Gibilterra/292
Currency: Bolivian Mvdol/Mvdol Boliviano/984
Currency: Bulgarian Lev/Nuovo Lev Bulgaro/975
Currency: Belgian Franc/Franco Belga/56
Currency: Kazakhstani Tenge/Tenge Kazaco/398
Currency: Solomon Islands Dollar/Dollaro delle Isole Solomon/90
Currency: Costa Rican Colón/Colón Costaricano/188
Currency: Swiss Franc/Franco Svizzero/756
Currency: Turkish Lira/Turkish Lira/949
Currency: Australian Dollar/Dollaro Australiano/36
Currency: CFA Franc BCEAO/Franco CFA BCEAO/952
Currency: Uzbekistan Som/Sum dell’Uzbekistan/860
Currency: European Unit of Account (XBD)/Unità di acconto europea (XBD)/958
Currency: Chinese Yuan/Renmimbi Cinese/156
Currency: Malawian Kwacha/Kwacha Malawiano/454
Currency: Bhutanese Ngultrum/Ngultrum Butanese/64
Currency: Zimbabwean Dollar (2009)/Zimbabwean Dollar (2009)/932
Currency: Special Drawing Rights/Diritti Speciali di Incasso/960
Currency: Italian Lira/Lira Italiana/380
Currency: Moroccan Dirham/Dirham Marocchino/504
Currency: Chilean Unit of Account (UF)/Unidades de Fomento Chilene/990
Currency: Lesotho Loti/Loti del Lesotho/426
Currency: Nigerian Naira/Naira Nigeriana/566
Currency: Guinea-Bissau Peso/Peso della Guinea-Bissau/624
Currency: Sudanese Pound/Sterlina sudanese/938
Currency: Lebanese Pound/Sterlina Libanese/422
Currency: Mauritian Rupee/Rupia Mauriziana/480
Currency: Testing Currency Code/Testing Currency Code/963
Currency: Latvian Lats/Lat Lettone/428
Currency: Japanese Yen/Yen Giapponese/392
Currency: Turkish Lira (1922-2005)/Lira Turca/792
Currency: Norwegian Krone/Corona Norvegese/578
Currency: Indian Rupee/Rupia Indiana/356
Currency: Hungarian Forint/Fiorino Ungherese/348
Currency: Tunisian Dinar/Dinaro Tunisino/788
Currency: Congolese Franc/Franco Congolese/976
Currency: Andorran Peseta/Peseta Andorrana/20
Currency: Palladium/Palladio/964
Currency: Liberian Dollar/Dollaro Liberiano/430
Currency: Netherlands Antillean Guilder/Fiorino delle Antille Olandesi/532
Currency: US Dollar (Same day)/Dollaro Statunitense (Same day)/998
Currency: Somali Shilling/Scellino Somalo/706
Currency: Mexican Peso/Peso Messicano/484
Currency: Zimbabwean Dollar (1980-2008)/Dollaro dello Zimbabwe/716
Currency: British Pound Sterling/Sterlina Inglese/826
Currency: Albanian Lek/Lek Albanese/8
Currency: Jordanian Dinar/Dinaro Giordano/400
Currency: East Caribbean Dollar/Dollaro dei Caraibi Orientali/951
Currency: Cuban Convertible Peso/Cuban Convertible Peso/931
Currency: Gold/Oro/959
Currency: Czech Republic Koruna/Corona Ceca/203
Currency: US Dollar/Dollaro Statunitense/840
Currency: Cuban Peso/Peso Cubano/192
Currency: Comorian Franc/Franco Comoriano/174
Currency: Pakistani Rupee/Rupia del Pakistan/586
Currency: Fijian Dollar/Dollaro delle Figi/242
Currency: French UIC-Franc/Franco UIC Francese/0
Currency: Vietnamese Dong/Dong Vietnamita/704
Currency: Honduran Lempira/Lempira Hoduregno/340
Currency: Brunei Dollar/Dollaro del Brunei/96
Currency: Finnish Markka/Markka Finlandese/246
Currency: European Monetary Unit/Unità monetaria europea/956
Currency: United Arab Emirates Dirham/Dirham degli Emirati Arabi Uniti/784
Currency: Algerian Dinar/Dinaro Algerino/12
Currency: South African Rand/Rand Sudafricano/710
Currency: Burundian Franc/Franco del Burundi/108
Currency: Bangladeshi Taka/Taka Bangladese/50
Currency: Paraguayan Guarani/Guarani del Paraguay/600
Currency: XSU/XSU/994
Currency: Peruvian Nuevo Sol/Sol Nuevo Peruviano/604
Currency: Ghanaian Cedi (1979-2007)/Cedi del Ghana/288
Currency: North Korean Won/Won Nordcoreano/408
Currency: Slovenian Tolar/Tallero Sloveno/705
Currency: Philippine Peso/Peso delle Filippine/608
Currency: Mauritanian Ouguiya/Ouguiya della Mauritania/478
Currency: Unknown Currency/Nessuna valuta/999
Currency: Azerbaijani Manat (1993-2006)/Manat Azero (1993-2006)/31
Currency: Cayman Islands Dollar/Dollaro delle Isole Cayman/136
Currency: Croatian Kuna/Kuna Croata/191
Currency: Botswanan Pula/Pula del Botswana/72
Currency: Saint Helena Pound/Sterlina di Sant’Elena/654
Currency: AYM/AYM/945
Currency: Ugandan Shilling/Scellino Ugandese/800
Currency: Austrian Schilling/Scellino Austriaco/40
Currency: Malaysian Ringgit/Ringgit della Malesia/458
Currency: French Gold Franc/Franco Oro Francese/0
Currency: Irish Pound/Sterlina irlandese/372
Currency: Vanuatu Vatu/Vatu di Vanuatu/548
Currency: Serbian Dinar/Dinaro serbo/941
Currency: Iranian Rial/Rial Iraniano/364
Currency: Timorese Escudo/Escudo di Timor/626
Currency: Mexican Investment Unit/Unidad de Inversion (UDI) Messicana/979
Currency: Iraqi Dinar/Dinaro Iracheno/368
Currency: Romanian Leu (1952-2006)/Leu della Romania/946
Currency: Moldovan Leu/Leu Moldavo/498
Currency: Slovak Koruna/Corona Slovacca/703
Currency: Israeli New Sheqel/Nuovo sheqel israeliano/376
Currency: Polish Zloty/Zloty Polacco/985
Currency: Seychellois Rupee/Rupia delle Seychelles/690
Currency: European Unit of Account (XBC)/Unità di acconto europea (XBC)/957
Currency: Yugoslavian New Dinar (1994-2002)/Dinaro Noviy Yugoslavo/891
Currency: Macedonian Denar/Dinaro Macedone/807
Currency: Belarusian Ruble/Rublo Bielorussia/974
Currency: Egyptian Pound/Sterlina Egiziana/818
Currency: Hong Kong Dollar/Dollaro di Hong Kong/344
Currency: Guyanaese Dollar/Dollaro della Guyana/328
Currency: Bosnia-Herzegovina Convertible Mark/Marco Conv. Bosnia-Erzegovina/977
Currency: Thai Baht/Baht Tailandese/764
Currency: Kuwaiti Dinar/Dinaro Kuwaitiano/414
Currency: Kenyan Shilling/Scellino Keniota/404
Currency: Icelandic Króna/Corona Islandese/352
Currency: Falkland Islands Pound/Sterlina delle Falkland/238
Currency: Angolan Kwanza/Kwanza Angolano/973
Currency: Bulgarian Hard Lev/Lev Bulgaro/100
Currency: Malagasy Ariary/Ariary Malgascio/969
Currency: Surinamese Dollar/Dollaro surinamese/968
Currency: Dominican Peso/Peso Dominicano/214
Currency: Tongan Pa?anga/Pa?anga di Tonga/776
Currency: Papua New Guinean Kina/Kina della Papua Nuova Guinea/598
Currency: Cape Verdean Escudo/Escudo del Capo Verde/132
Currency: Namibian Dollar/Dollaro Namibiano/516
Currency: Uruguayan Peso/Peso Uruguayo uruguaiano/858
Currency: Ethiopian Birr/Birr Etiopico/230
Currency: Trinidad and Tobago Dollar/Dollaro di Trinidad e Tobago/780
Currency: Salvadoran Colón/Colón Salvadoregno/222
Currency: Brazilian Real/Real Brasiliano/986
Currency: Silver/Argento/961
Currency: Tajikistani Somoni/Somoni del Tajikistan/972
Currency: European Composite Unit/Unità composita europea/955
Currency: Lithuanian Litas/Lita Lituana/440
Currency: Estonian Kroon/Corona dell’Estonia/233
Currency: Platinum/Platinum/962
Currency: Haitian Gourde/Gourde Haitiano/332
Currency: Belarusian New Ruble (1994-1999)/Nuovo Rublo Bielorussia (1994-1999)/112
Currency: South Korean Won/Won Sudcoreano/410
Currency: Azerbaijani Manat/Azerbaijani Manat/944
Currency: Nepalese Rupee/Rupia Nepalese/524
Currency: Cambodian Riel/Riel Cambogiano/116
Currency: Zambian Kwacha/Kwacha dello Zambia/894
Currency: New Taiwan Dollar/Nuovo dollaro taiwanese/901
Currency: CFA Franc BEAC/Franco CFA BEAC/950
Currency: Cypriot Pound/Sterlina Cipriota/196
Currency: Afghan Afghani/Afgani/971
Currency: Aruban Florin/Fiorino di Aruba/533
Currency: Canadian Dollar/Dollaro Canadese/124
Currency: Mozambican Metical (1980-2006)/Mozambican Metical (1980-2006)/508
Currency: Ghanaian Cedi/Cedi ghanese/936
Currency: German Mark/Marco Tedesco/276
Currency: Swedish Krona/Corona Svedese/752

This blog post has briefly looked at the new class-level method and three new instance-level methods added to the Currency class.