Java 7 New Features Cookbook

By Richard M. Reese , Jennifer L. Reese
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Java Language Improvements

About this book

Java 7 is a major update that includes a lot of exciting new language improvements such as support for type inference and improved exception handling. Other new features include the ability to work with symbolic links, a greatly simplified directory traversal technique, and the monitoring of file creation and deletion. Improvements in event handling, security, and concurrent processing have also been added

Java 7 New Features Cookbook is your go-to guide to learn about all the new exciting features Java 7 has to offer with a very practical recipe-based approach.

The book starts with coverage of the new language improvements. Subsequent chapters address the new features of Java 7 while incorporating these new language improvements when possible.

The new NIO techniques provide enhanced capabilities which are complemented by the new try-with-resources block and enhanced generic support. The new JLayer decorator and improved window methods enhance the developer’s ability to create GUI applications.

The Java 7 New Features Cookbook provides a comprehensive coverage of the exciting features in Java 7.

Publication date:
February 2012
Publisher
Packt
Pages
384
ISBN
9781849685627

 

Chapter 1. Java Language Improvements

In this chapter, we will cover the following:

  • Using string literals in switch statements

  • Using underscores in literals to improve code readability

  • Using the try-with-resources block to improve exception handling code

  • Creating a resource that can be used with the try-with-resources technique

  • Catching multiple exception types to improve type checking

  • Re-throwing exceptions in Java 7

  • Using the diamond operator for constructor type inference

  • Using the @SafeVarargs annotation

Introduction

Java 7 was released in July of 2011 and introduced a number of new features. In the Java SDK documentation, you may see it referred to as Java 1.7. This chapter will focus on those that have been grouped as part of the Project Coin (http://openjdk.java.net/projects/coin/). Project Coin refers to the small language changes in Java 7 that are designed to make programs more readable by removing extra text when possible. The changes to the language do not involve modifying the Java Virtual Machine (JVM). These new features include:

  • The use of strings in switch statements

  • The addition of binary literals and the ability to insert underscores into numeric literals

  • The use of a multi-catch block

  • The try-with-resources block

  • Improved type inferences using the diamond operator

  • Improvements in the use of methods with a variable number of arguments

Since the inception of Java, only integer values could be used to control a switch statement. Strings can now be used and can provide a more convenient technique for controlling the execution flow that is based on a string. The Using string literals in switch statements recipe illustrates this feature.

Underscores can now be used with literals as examined in the recipe Using underscores in literals to improve code readability. These can make a program more readable and maintainable. In addition, binary literals can now be used. Instead of using a hexadecimal literal, for example, the literal bit pattern can be used.

New to Java 7 are the improved try-catch block mechanisms. These include the ability to catch more than one exception from a single catch block, and improvements in how exceptions can be thrown. The Catching multiple exception types to improve type checking recipe looks into these enhancements.

Another improvement in exception handling involves the automatic closure of resources. In earlier versions of Java, when multiple resources were opened in a try block, it could be difficult to effectively close the resources, when an exception occurs. Java 7 provides a new technique as discussed in the Using the try-with-resources block to improve exception handling code recipe.

To take advantage of this technique, a class representing a resource must implement the new java.lang.AutoCloseable interface. This interface consists of a single method, close which, when implemented, should release resources as needed. Many core Java classes have been augmented to do this. The recipe: Creating a resource that can be used with the try-with-resources technique illustrates how to do this for non-core classes.

Java 7 provides the capability to re-throw exceptions in a flexible manner. It provides a more precise way of throwing exceptions, and more flexibility in how they can be handled in a try/catch bock. The Re-throwing exceptions in Java 7 recipe illustrates this capability.

When generics were introduced in Java 1.5, it became easier to write code to address a number of similar problems. However, its usage at times could become somewhat verbose. The introduction of the diamond operator has eased this burden, and is illustrated in the Using the diamond operator for constructor type inference recipe.

When a method uses a variable number of generic arguments, sometimes an invalid warning is generated. The @SafeVarargs annotation has been introduced to flag a method as safe. This issue is related to heap pollution and is discussed in the Using the @SafeVarargs Annotation recipe.

Note

In this and the other chapters, most of the code examples will be written to execute from within a main method. While no specific Integrated Development Environment (IDE) is needed to use the new features of Java 7, the examples in this book were developed using NetBeans 7.0.1 and Windows 7, unless otherwise noted. At minimum, a version of the Java Development Kit (JDK) 1.7 or later is needed.

Also, note that the code examples provided do not include import statements. These are not shown here to reduce the number of lines of code. Most IDEs make it easy to insert these imports, but you need to be careful that the correct imports are used.

 

Introduction


Java 7 was released in July of 2011 and introduced a number of new features. In the Java SDK documentation, you may see it referred to as Java 1.7. This chapter will focus on those that have been grouped as part of the Project Coin (http://openjdk.java.net/projects/coin/). Project Coin refers to the small language changes in Java 7 that are designed to make programs more readable by removing extra text when possible. The changes to the language do not involve modifying the Java Virtual Machine (JVM). These new features include:

  • The use of strings in switch statements

  • The addition of binary literals and the ability to insert underscores into numeric literals

  • The use of a multi-catch block

  • The try-with-resources block

  • Improved type inferences using the diamond operator

  • Improvements in the use of methods with a variable number of arguments

Since the inception of Java, only integer values could be used to control a switch statement. Strings can now be used and can provide a more convenient technique for controlling the execution flow that is based on a string. The Using string literals in switch statements recipe illustrates this feature.

Underscores can now be used with literals as examined in the recipe Using underscores in literals to improve code readability. These can make a program more readable and maintainable. In addition, binary literals can now be used. Instead of using a hexadecimal literal, for example, the literal bit pattern can be used.

New to Java 7 are the improved try-catch block mechanisms. These include the ability to catch more than one exception from a single catch block, and improvements in how exceptions can be thrown. The Catching multiple exception types to improve type checking recipe looks into these enhancements.

Another improvement in exception handling involves the automatic closure of resources. In earlier versions of Java, when multiple resources were opened in a try block, it could be difficult to effectively close the resources, when an exception occurs. Java 7 provides a new technique as discussed in the Using the try-with-resources block to improve exception handling code recipe.

To take advantage of this technique, a class representing a resource must implement the new java.lang.AutoCloseable interface. This interface consists of a single method, close which, when implemented, should release resources as needed. Many core Java classes have been augmented to do this. The recipe: Creating a resource that can be used with the try-with-resources technique illustrates how to do this for non-core classes.

Java 7 provides the capability to re-throw exceptions in a flexible manner. It provides a more precise way of throwing exceptions, and more flexibility in how they can be handled in a try/catch bock. The Re-throwing exceptions in Java 7 recipe illustrates this capability.

When generics were introduced in Java 1.5, it became easier to write code to address a number of similar problems. However, its usage at times could become somewhat verbose. The introduction of the diamond operator has eased this burden, and is illustrated in the Using the diamond operator for constructor type inference recipe.

When a method uses a variable number of generic arguments, sometimes an invalid warning is generated. The @SafeVarargs annotation has been introduced to flag a method as safe. This issue is related to heap pollution and is discussed in the Using the @SafeVarargs Annotation recipe.

Note

In this and the other chapters, most of the code examples will be written to execute from within a main method. While no specific Integrated Development Environment (IDE) is needed to use the new features of Java 7, the examples in this book were developed using NetBeans 7.0.1 and Windows 7, unless otherwise noted. At minimum, a version of the Java Development Kit (JDK) 1.7 or later is needed.

Also, note that the code examples provided do not include import statements. These are not shown here to reduce the number of lines of code. Most IDEs make it easy to insert these imports, but you need to be careful that the correct imports are used.

 

Using string literals in switch statements


The ability to use string literals in switch statements is new to Java 7. Previously, only integer values were the valid arguments in a switch statement. It is not uncommon to need to make a decision based on a string value, and the use of a switch statement to perform this task can simplify the series of if statements that would otherwise be needed. This can result in more readable and efficient code.

Getting ready

A selection based on a string value may occur in an application. Once such a situation is identified, do the following:

  1. 1. Create a String variable to be processed via the switch statement.

  2. 2. Create the switch block, using string literals for the case clauses.

  3. 3. Use the String variable to control the switch statement.

How to do it...

The example demonstrated here will use a switch statement to process an application's command line arguments. Create a new console application. In the main method, we will use the args argument to process the application's command line arguments. Many applications allow command line arguments to customize or otherwise affect the operation of the application. In this example, our application will support a verbose mode, logging, and provide a help message regarding the valid command line arguments for the application.

  1. 1. In this example, create a class called StringSwitchExample that possesses three instance variables to be set by the command line arguments, shown as follows:

    public class StringSwitchExample {
    private static boolean verbose = false;
    private static boolean logging = false;
    private static boolean displayHelp = false;
    }
    

    Note

    Downloading the example code

    You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

  2. 2. Next, add the following main method, which will set these variables based on the command line arguments provided:

    public static void main(String[] args) {
    for (String argument : args) {
    switch (argument) {
    case "-verbose":
    case "-v":
    verbose = true;
    switch statementsstring literals, usingbreak;
    case "-log":
    logging = true;
    break;
    case "-help":
    displayHelp = true;
    break;
    default:
    System.out.println("Illegal command line argument");
    }
    }
    displayApplicationSettings();
    }
    
  3. 3. Add the following helper method to display the application setting:

    private static void displayApplicationSettings() {
    System.out.println("Application Settings");
    System.out.println("Verbose: " + verbose);
    System.out.println("Logging: " + logging);
    System.out.println("Help: " + displayHelp);
    }
    
  4. 4. Execute the application using the following command line:

    java StringSwitchExample -verbose -log
    
  5. 5. If you are using an IDE, then there is usually a way to set the command line arguments. For example, in NetBeans, right-clicking on the project name in the Project window, and selecting Properties menu will open a Project Properties dialog box. In the Run category, the Arguments textbox allows you to set the command line arguments, as shown in the following screenshot:

  6. 6. When the application is executed, your output should appear as follows:

    Application Settings

    Verbose: true

    Logging: true

    Help: false

How it works...

The application setting variables are all initialized to false. A for-each loop iterates through each command line argument. The switch statement uses a specific command line argument to turn on an application setting. The switch statement behaves like the earlier Java switch statements.

Note

It is interesting to note that the Java Virtual Machine (JVM) currently provides no direct support for switching with strings. The Java compiler is responsible for converting strings in switch statements to the appropriate byte code.

When the for loop completes, the displayApplicationSettings method is invoked. This displays the current application setting, reflecting the configuration specified by the command line arguments.

It is important to note, however, while a String variable may be passed to the switch statements, as with the other data types used in switch statements, the strings used in the case clauses must be string literals. The general rules regarding switch statements apply when using string literals. Each statement within the switch block must have a valid non-null label, no two labels may be identical, and only one default label may be associated with each switch block.

There's more...

When using strings, you need to be careful about the following two issues:

  • Null values for strings

  • The case of the string

Using a string reference variable that is assigned a null value will result in a java.lang.NullPointerException. See the Handling null references recipe in Chapter 11, Odds and Ends, for more information on how to handle a NullPointerException. This is also true when used with a switch statement. Also, the evaluation of a case expression is case sensitive in a switch statement. In the previous example, if the command line argument is different from what appears in the case expression, then the case is skipped. If we had used the following command line instead, where we capitalized the word verbose:

java StringSwitchExample -Verbose -log

Then the verbose mode will no longer be used as indicated in the following output:

Application Settings

Verbose: false

Logging: true

Help: false

 

Using underscores in literals to improve code readability


Numerical literals can contain underscore characters (_) in Java 7. This is intended to improve the readability of code by separating digits of a literal into significant groups at almost any arbitrary place that meets the needs of the developer. The underscore can be applied to primitive data types in any supported base (binary, octal, hexadecimal, or decimal), and to both integer and floating-point literals.

Getting ready

The first step is to identify instances where it will be beneficial for the developer to format literals in such a manner. Typically, you will want to identify longer numbers or numbers that would have significant parts in their external form, such as debit card numbers. The basic steps include:

  1. 1. Identify a literal to use with underscores.

  2. 2. Insert underscores at appropriate places within the literal to make the literal more readable.

How to do it...

This example illustrates using underscores to clarify the inherent gaps found in most debit card numbers, and demonstrates their use with floating point numbers.

  1. 1. Create a new console application and add the main method as follows:

    public static void main(String[] args) {
    long debitCard = 1234_5678_9876_5432L;
    System.out.println("The card number is: " + debitCard);
    System.out.print("The formatted card number is:");
    printFormatted(debitCard);
    float minAmount = 5_000F;
    float currentAmount = 5_250F;
    float withdrawalAmount = 500F;
    if ((currentAmount - withdrawalAmount) < minAmount) {
    System.out.println("Minimum amount limit exceeded " + minAmount);
    }
    }
    
  2. 2. Add a method to display the credit card number properly formatted for output, as follows:

    private static void printFormatted(long cardNumber) {
    String formattedNumber = Long.toString(cardNumber);
    for (int i = 0; i < formattedNumber.length(); i++) {
    if (i % 4 == 0) {
    System.out.print(" ");
    }
    System.out.print(formattedNumber.charAt(i));
    }
    System.out.println();
    }
    
  3. 3. Execute the application. The output will appear as follows:

    The card number is: 1234567898765432

    The formatted card number is: 1234 5678 9876 5432

    Minimum amount limit exceeded 5000.0

Notice that in the first output line the displayed number does not contain underscores, but our second line is formatted to use spaces where the underscores were. This is to illustrate the difference between how the number looks internally, and how it needs to be formatted for external display.

How it works...

The debit card example partitioned the number into four sections making it more readable. A long variable was needed due to the length of the debit card number.

Next, a minimum limit was placed on the amount of money in a bank account. The variable minAmount of type float was set to 5,000.00 using the underscores to denote the location of the comma. Two more float called currentAmount and withdrawalAmount were declared and set equal to 5,250.00 and 500.00, respectively. The code then determined whether the withdrawalAmount could be subtracted from the currentAmount and still maintain a balance above the minAmount. If not, a message to that effect was displayed.

Note

In most applications involving currency, the java.util.Currency class would be a more appropriate choice. The previous example used floating point literals only to explain the usage of underscores.

The only purpose of the underscore is to make the code more readable to the developer. The compiler ignores the underscores during code generation and during any subsequent variable manipulation. Consecutive underscores are treated as one and also ignored by the compiler. If the output format of a variable is important, it will have to be handled separately.

There's more...

Underscores can be used for more than base 10 literals. In addition, underscores can be misused. Here, we will address the following:

  • Simple underscore usage mistakes

  • Using underscores with hexadecimal literals

  • Using underscores with binary literals

Simple underscore usage mistakes

Underscores may generally be placed arbitrarily within the literals, but there are guidelines limiting their use. It is invalid to place underscores at the beginning or end of a number, adjacent to a decimal point when used in a float or double, prior to the D, F, or L suffix, or where a string of digits is required.

The following are the examples of invalid underscore usages:

long productKey = _12345_67890_09876_54321L;
float pi = 3._14_15F;
long licenseNumber = 123_456_789_L;

These will generate the syntax error, error: illegal underscore.

Using underscores with hexadecimal literals

Underscores can be particularly useful when dealing with binary data expressed in hexadecimal or binary. In the following example, an integer value representing a command to be sent to a data port was expressed as a hexadecimal and as a binary literal:

int commandInHex = 0xE_23D5_8C_7;
int commandInBinary = 0b1110_0010001111010101_10001100_0111;

These two numbers are the same. They are only expressed in different bases. Here, we used base 2 and base 16. The base 16 representation may be more readable in this example. Base 2 literals will be discussed in more depth in the next section.

The underscores were used to more clearly identify parts of the command. The assumption is that the first four bits of the command represent an operator, while the next 16 bits are an operand. The next 8 bits and 4 bits could represent other aspects of the command.

Using underscores with binary literals

We can also use underscores with binary literals. For example, to initialize a device we may need to send a specific 8 bit sequence to the data port. This sequence may be organized such that the first two bits specify the operation (read, write, and so on), the next three bits may specify a device resource, and the last three bits could represent an operand. We may encode this sequence using a binary literal with underscores as follows:

byte initializationSequence = 0b10_110_010;

Use of the underscores clearly identifies each field. While it is not necessary to use the variable initializationSequence, it allows us to use the sequence in more than one place in a program. Another example defines a mask where, in this case, the first three bits are eliminated during an AND operation as follows:

result = inputValue & 0b000_11111;

In a bitwise AND operation, each bit of the operands are Anded with each other. These examples are illustrated as follows:

byte initializationSequence = (byte) 0b01_110_010;
byte inputValue = (byte) 0b101_11011;
byte result = (byte) (inputValue & (byte) 0b000_11111);
System.out.println("initializationSequence: " +
Integer.toBinaryString(initializationSequence));
System.out.println("result: " + Integer.toBinaryString(result));

When this sequence is executed, we get the following output:

initializationSequence: 1110010

result: 11011

The byte cast operator was needed because binary literals default to type int. Also, notice that the toBinaryString method does not display leading zeroes.

 

Using the try-with-resources block to improve exception handling code


Prior to Java 7, the code required for properly opening and closing resources, such as a java.io.InputStream or java.nio.Channel, was quite verbose and prone to errors. The try-with-resources block has been added in an effort to simplify error-handling and make the code more concise. The use of the try-with-resources statement results in all of its resources being automatically closed when the try block exits. Resources declared with the try-with-resources block must implement the interface java.lang.AutoCloseable.

This approach enables a better programming style as it avoids nested and excessive try-catch blocks. It also ensures accurate resource management, which you may see referred to as Automated Resource Management (ARM) in literature.

Getting ready

When working with resources that need to be opened and closed, the try-with-resource block is implemented by:

  1. 1. Creating the try block and declaring the resources to be managed.

  2. 2. Using the resource within the try block.

How to do it...

  1. 1. Create a console application and add the following main method to it. Create a text file in the working directory called users.txt and add a list of names to the file. This example opens up that file and creates a backup, while demonstrating the use of the try-with-resources technique, where a java.io.BufferedReader and java.io.BufferedWriter objects are created with the try block:

    public static void main(String[] args) {
    try (BufferedReader inputReader = Files.newBufferedReader(
    Paths.get(new URI ("file:///C:/home/docs/users.txt")),
    Charset.defaultCharset());
    BufferedWriter outputWriter = Files.newBufferedWriter(
    Paths.get(new URI("file:///C:/home/docs/users.bak")),
    Charset.defaultCharset())) {
    String inputLine;
    while ((inputLine = inputReader.readLine()) != null) {
    outputWriter.write(inputLine);
    outputWriter.newLine();
    }
    System.out.println("Copy complete!");
    }
    catch (URISyntaxException | IOException ex) {
    ex.printStackTrace();
    }
    }
    
  2. 2. Execute the application. The output should be as follows:

    Copy complete!

How it works...

The resources to be managed are declared and initialized inside a set of parentheses between the try keyword and the opening curly brace of the try block. In this case, two resources are created. The first is a BufferedReader object associated with the users.txt file and the second is a BufferedWriter object associated with the users.bak file. The new IO techniques using the java.nio.file.Path interface are discussed in Chapter 6, Stream IO in Java 7.

The first file is then read line by line and written to the second file. When the try block is exited, the two IO streams are automatically closed. A message is then displayed showing that the copy operation is complete.

Notice the use of the vertical bar in the catch block. This is new to Java 7 and allows us to catch multiple exceptions in a single catch block. The use of this operator is discussed in the Catching multiple exception types to improve type checking recipe.

Bear in mind that the resources declared with a try-with-resources block are separated by semicolons. Failure to do so will result in a compile-time error. Also, resources will be attempted to be closed, regardless of whether the try block completes normally or not. If the resource cannot be closed, an exception is normally thrown.

Regardless of whether resources are closed or not, the catch and finally blocks are always executed. However, exceptions can still be thrown from these blocks. This is discussed in more detail in the Creating a resource that can be used with the try-with-resources technique recipe.

There's more...

To complete our understanding of the try-with-resources technique, we need to address two other topics as follows:

  • Understanding suppressed exceptions

  • Structuring issues when using the try-with-resources technique

Understanding suppressed exceptions

In support of this approach, a new constructor was added to the java.lang.Exception class along with two methods: addSuppressed and getSuppressed. Suppressed exceptions are those exceptions that are not explicitly reported. In the case of the try-with-resources try block, exceptions may be thrown from the try block itself or when the resources created by the try block are closed. When more than one exception is thrown, exceptions may be suppressed.

In the case of the try-with-resources block, any exceptions associated with a close operation are suppressed when an exception is thrown from the block itself. This is demonstrated in the Creating a resource that can be used with the try-with-resources technique recipe.

Suppressed exceptions can be retrieved using the getSuppressed method. Programmer created exceptions can designate an exception as suppressed by using the addSuppressed method.

Structuring issues when using the try-with-resources technique

It may not be desirable to use this technique when a single resource is used. We will show three different implementations of a sequence of code to display the contents of the users.txt file. The first, as shown in the following code, uses the try-with-resources block. However, it is necessary to precede this block with a try block to capture the java.net.URISyntaxException:

Path path = null;
try {
path = Paths.get(new URI("file:///C:/home/docs/users.txt"));
}
catch (URISyntaxException e) {
System.out.println("Bad URI");
}
try (BufferedReader inputReader = Files.newBufferedReader(path, Charset.defaultCharset())) {
String inputLine;
while ((inputLine = inputReader.readLine()) != null) {
System.out.println(inputLine);
}
}
catch (IOException ex) {
ex.printStackTrace();
}

This example is predicated upon the need to catch the URISyntaxException. This can be avoided by creating the java.net.URI object inside of the get method as shown below. However, it does make the code harder to read:

try (BufferedReader inputReader = Files.newBufferedReader(
Paths.get(new URI("file:///C:/home/docs/users.txt")), Charset.defaultCharset())) {
String inputLine;
while ((inputLine = inputReader.readLine()) != null) {
System.out.println(inputLine);
}
}
catch (IOException | URISyntaxException ex) {
ex.printStackTrace();
}

Notice the use of the multiple catch block as discussed in the Catching multiple exception types to improve type checking recipe. Another approach is to avoid the URI object altogether by using the get method with a String argument as follows:

try {
Path path = Paths.get("users.txt");
BufferedReader inputReader =
Files.newBufferedReader(path, Charset.defaultCharset());
String inputLine;
while ((inputLine = inputReader.readLine()) != null) {
System.out.println(inputLine);
}
}
catch (IOException ex) {
ex.printStackTrace();
}

The methods that are used and the structure of the code affect the readability and maintainability of the code. It may or may not be feasible to eliminate the use of the URI object, or similar objects, in a code sequence. However, careful consideration of alternative approaches can go a long way to improving an application.

See also

The Catching multiple exception types to improve type checking recipe and Creating a resource that can be used with the try-with-resources technique recipe provide further coverage of the exception handling in Java 7.

 

Creating a resource that can be used with the try-with-resources technique


There are many resources in Java libraries, which can be used as part of the try-with-resource technique. However, there may be times when you may wish to create your own resources that can be used with this technique. An example of how to do this is illustrated in this recipe.

Getting ready

To create a resource that can be used with the try-with-resources technique:

  1. 1. Create a class that implements the java.lang.AutoCloseable interface.

  2. 2. Override the close method.

  3. 3. Implement resource-specific methods.

Any objects created with the try-with-resources block must implement the AutoCloseable interface. This interface has a single method, that is, close.

How to do it...

Here, we will illustrate this approach by creating three classes:

  • One class that contains the main method

  • Two classes that implement the AutoCloseable interface

  1. 1. Create two classes called FirstAutoCloseableResource and SecondAutoCloseableResource. Within these classes, implement a manipulateResource and close method, shown as follows:

    public class FirstAutoCloseableResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
    // Close the resource as appropriate
    System.out.println("FirstAutoCloseableResource close method executed");
    throw new UnsupportedOperationException(
    "A problem has occurred in FirstAutoCloseableResource");
    }
    public void manipulateResource() {
    // Perform some resource specific operation
    System.out.println("FirstAutoCloseableResource manipulateResource method executed");
    try-with-resource blockresource, creating}
    }
    public class SecondAutoCloseableResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
    // Close the resource as appropriate
    System.out.println("SecondAutoCloseableResource close method executed");
    throw new UnsupportedOperationException(
    "A problem has occurred in SecondAutoCloseableResource");
    }
    public void manipulateResource() {
    // Perform some resource specific operation
    System.out.println("SecondAutoCloseableResource manipulateResource method executed");
    }
    }
    
  2. 2. Next, add the following code to a main method. We use the try-with-resources technique with the two resources, and then call their manipulateResource method:

    try (FirstAutoCloseableResource resource1 = new FirstAutoCloseableResource();
    SecondAutoCloseableResource resource2 = new SecondAutoCloseableResource()) {
    resource1.manipulateResource();
    resource2.manipulateResource();
    }
    catch (Exception e) {
    e.printStackTrace();
    for(Throwable throwable : e.getSuppressed()) {
    System.out.println(throwable);
    }
    }
    
  3. 3. When the code executes, the close methods throw an UnsupportedOperationException shown as follows:

    FirstAutoCloseableResource manipulateResource method executed

    SecondAutoCloseableResource manipulateResource method executed

    SecondAutoCloseableResource close method executed

    FirstAutoCloseableResource close method executed

    java.lang.UnsupportedOperationException: A problem has occurred in SecondAutoCloseableResource

    at packt.SecondAutoCloseableResource.close(SecondAutoCloseableResource.java:9)

    at packt.TryWithResourcesExample.displayAutoCloseableExample(TryWithResourcesExample.java:30)

    at packt.TryWithResourcesExample.main(TryWithResourcesExample.java:22)

    Suppressed: java.lang.UnsupportedOperationException: A problem has occurred in FirstAutoCloseableResource

    at packt.FirstAutoCloseableResource.close(FirstAutoCloseableResource.java:9)

    ... 2 more

    java.lang.UnsupportedOperationException: A problem has occurred in FirstAutoCloseableResource

How it works...

Within the resource classes, the manipulateResource methods were created to perform some resource-specific operation. The resource classes were declared as part of the try block, and the manipulateResource methods were called. This was illustrated in the first part of the output. The output has been highlighted to clarify the process.

When the try block terminated, the close methods were executed. They were executed in an opposite order than expected. This is the result of how the application program stack works.

Within the catch block, the stack was dumped. In addition, we used the getSuppressed method to return and display the suppressed methods. Support for suppressed exceptions was introduced in Java 7. These types of exceptions are discussed in the Using the try-with-resource block to improve exception handling code recipe and later on in this recipe.

There's more...

Within the close method, one of the following three actions is possible:

  • Do nothing if there is nothing to close or the resource will always close

  • Close the resource and return without error

  • Attempt to close the resource, but throw an exception upon failure

The first two conditions are easy enough to handle. In the case of the last one, there are a few things to bear in mind.

Always implement the close method and supply specific exceptions. This provides the user with more meaningful feedback concerning the underlying problem. Also, do not throw an InterruptedException. Runtime problems can occur if the InterruptedException has been suppressed.

The close method is not required to be idempotent. An idempotent method is the one where repeated execution of the method will not cause problems. As an example, reading from the same file twice will not necessarily cause problems. Whereas, writing the same data twice to the file may. The close method does not have to be idempotent, however, it is recommended that it should be.

See also

The Using the try-with-resources block to improve exception handling code recipe covers the use of this type of try block.

 

Catching multiple exception types to improve type checking


Within a try block, multiple exceptions can be generated and thrown. A corresponding series of catch blocks are used to capture and then deal with the exceptions. Frequently, the action needed to deal with one exception is the same for other exceptions. An example of this is when the logging of an exception is performed.

In Java 7, it is now possible to handle more than one exception from within a single catch block. This ability can reduce the duplication of code. In earlier versions of Java, there was often a temptation to address this issue by catching a higher-level exception class and handling multiple exceptions from that block. There is less need for this approach now.

Getting ready

Using a single catch block to capture multiple exceptions is achieved by:

  1. 1. Adding a catch block

  2. 2. Including multiple exceptions within the catch blocks' parentheses, separated by a vertical bar

How to do it...

In this example, we wish to deal with invalid input from the user by logging an exception. This is a simple approach that will suffice to explain how multiple exceptions can be handled.

  1. 1. Create an application with two classes: MultipleExceptions and InvalidParameter. The InvalidParameter class is used to handle invalid user input, and the MultipleExceptions class contains the main method and example code.

  2. 2. Create the InvalidParameter class as follows:

    public class InvalidParameter extends java.lang.Exception {
    public InvalidParameter() {
    super("Invalid Parameter");
    }
    }
    
  3. 3. Next, create the MultipleExceptions class with a java.util.logging.Logger object as follows:

    public class MultipleExceptions {
    private static final Logger logger = Logger.getLogger("log.
    txt");
    public static void main(String[] args) {
    System.out.print("Enter a number: ");
    try {
    Scanner scanner = new Scanner(System.in);
    int number = scanner.nextInt();
    if (number < 0) {
    throw new InvalidParameter();
    }
    System.out.println("The number is: " + number);
    }
    catch (InputMismatchException | InvalidParameter e) {
    logger.log(Level.INFO, "Invalid input, try again");
    }
    }
    
  4. 4. Execute the program using a variety of input. Using a valid number, such as 12, results in the following output:

    Enter a number: 12

    The number is: 12

  5. 5. Using invalid input like a non-numeric value, such as cat, or a negative number, such as -5, will result in the following output:

    Enter a number: cat

    Invalid input, try again

    Aug 28, 2011 1:48:59 PM packt.MultipleExceptions main

    INFO: Invalid input, try again

    Enter a number: -5

    Invalid input, try again

    Aug 28, 2011 1:49:20 PM packt.MultipleExceptions main

    INFO: Invalid input, try again

How it works...

The logger was created and when an exception occurred, an entry was made in the logger file. The output created by using NetBeans also displayed these log messages as they occur.

When an exception was thrown, the catch block was entered. Notice that the two exceptions of interest here, java.util.InputMismatchException and InvalidParameter, occur within the same catch statement and are separated with a vertical bar. Also, notice that there is only a single variable, e, used to represent the exception.

This approach is useful when we need to handle a few specific exceptions, and need to handle them in the same way. When a catch block handles more than one exception, the catch block parameter is implicitly final. This means that it is not possible to assign new values to the parameter. The following is illegal and its use will result in a syntax error:

}
catch (InputMismatchException | InvalidParameter e) {
e = new Exception(); // multi-catch parameter e may not be assigned
logger.log(Level.INFO, "Invalid input, try again");
}

Besides being more readable and concise than using multiple catch blocks, the generated bytecode is also smaller and does not result in the generation of duplicate code.

There's more...

The base class or classes of a set of exceptions impact when to use a catch block to capture multiple exceptions. Also, assertions are useful in creating robust applications. These issues are addressed as follows:

  • The use of a common exception base class and the java.lang.ReflectiveOperationException

  • Using the java.lang.AssertionError class in Java 7

The use of a common exception base class and the ReflectiveOperationException

Catching multiple exceptions in the same catch block is useful when different exceptions need to be handled in the same way. However, if the multiple exceptions share a common base exception class, then it may be simpler to catch the base class exception instead. This is the case with many IOException derived classes.

For example, the Files class' delete method may throw one of the following four different exceptions:

  • java.nio.file.NoSuchFileException

  • java.nio.file.DirectoryNotEmptyException

  • java.io.IOException

  • java.lang.SecurityException

Of these, NoSuchFileException and DirectoryNotEmptyException are ultimately derived from IOException. Thus, catching the IOException may be sufficient as illustrated in the following code:

public class ReflectiveOperationExceptionExample {
public static void main(String[] args) {
try {
Files.delete(Paths.get(new URI("file:///tmp.txt")));
}
catch (URISyntaxException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}

In this example, notice that a URISyntaxException exception is potentially thrown by the URI constructor. The recipe Deleting a file or directory, in Chapter 4, Managing Files and Directories, details the use of the delete method.

In Java 7, a new exception, ReflectiveOperationException, has been added to the java.lang package. It is the base class for the following exceptions:

  • ClassNotFoundException

  • IllegalAccessException

  • InstantiationException

  • InvocationTargetException

  • NoSuchFieldException

  • NoSuchMethodException

This exception class can ease the handling of reflection type exceptions. The use of the multiple exceptions catching mechanism is more appropriate for those sets of exceptions which have no common base class.

Note

As a general rule, it is better to catch the exception that is as specific to the problem as possible. For example, it is better to catch a NoSuchFileException as opposed to the more broad Exception, when dealing with a missing file. This provides more detail about the exception.

Using the AssertionError class in Java 7

Assertions are useful in building an application that is more robust. A good introduction to this topic can be found at http://download.oracle.com/javase/1.4.2/docs/guide/lang/assert.html. In Java 7, a new constructor was added that allows a message to be attached to a user-generated assertion error. This constructor has two arguments. The first is the message to be associated with the AssertionError and the second is a Throwable clause.

In the MultipleExceptions class developed earlier in this recipe, we tested to see if the number was less than zero, and if so we threw an exception. Here, we will illustrate the use of the AssertionError constructor by throwing an AssertionError, if the number is greater than 10.

Add the following code to the main method near the original test of the number:

if(number>10) {
throw new AssertionError("Number was too big",new Throwable("Throwable assertion message"));
}

Execute the program and enter 12 again. Your results should be similar to the following:

Enter a number: 12

Exception in thread "main" java.lang.AssertionError: Number was too big

at packt.MultipleExceptions.main(MultipleExceptions.java:28)

Caused by: java.lang.Throwable: Throwable assertion message

... 1 more

Java Result: 1

Prior to Java 7, it was not possible to associate a message with a user-generated AssertionError.

See also

The use of the Files class is detailed in Chapter 4, Managing Files and Directories.

 

Rethrowing exceptions in Java 7


When an exception is caught in a catch block, it is sometimes desirable to rethrow the exception. This allows the exception to be processed by the current method and methods that called the current method.

However, prior to Java 7 only a base class exception could be rethrown. When more than one exception needed to be rethrown, you were restricted to declaring a common base class in the method declaration. Now, it is possible to be more restrictive on the exceptions which can be thrown for a method.

Getting ready

In order to rethrow exceptions in Java, you must first catch them. From within the catch block, use the throw keyword with the exception to be thrown. The new rethrow technique in Java 7 requires that you:

  • Use a base class exception class in the catch block

  • Use the throw keyword to throw the derived class exception from the catch block

  • Modify the method's signature to throw the derived exceptions

How to do it...

  1. 1. We will modify the ReflectiveOperationExceptionExample class developed in the Catching multiple exception types to improve type checking recipe. Modify the main method to call the deleteFile method in the try block, as shown in the following code:

    public class ReflectiveOperationExceptionExample {
    public static void main(String[] args) {
    try {
    deleteFile(Paths.get(new URI("file:///tmp.txt")));
    }
    catch (URISyntaxException ex) {
    ex.printStackTrace();
    }
    catch (IOException ex) {
    ex.printStackTrace();
    }
    }
    
  2. 2. Add the deleteFile method, shown as follows:

    private static void deleteFile(Path path) throws NoSuchFileException, DirectoryNotEmptyException {
    Java 7exceptions, rethrowingtry {
    Files.delete(path);
    }
    catch (IOException ex) {
    if(path.toFile().isDirectory()) {
    throw new DirectoryNotEmptyException(null);
    }
    else {
    throw new NoSuchFileException(null);
    }
    }
    }
    }
    
  3. 3. Execute the application using a file that does not exist. The output should be as follows:

    java.nio.file.NoSuchFileException

    at packt.ReflectiveOperationExceptionExample.deleteFile(ReflectiveOperationExceptionExample.java:33)

    at packt.ReflectiveOperationExceptionExample.main(ReflectiveOperationExceptionExample.java:16)

How it works...

The main method called and handled exceptions generated by the deleteFile call. The method declared that it can throw a NoSuchFileException and a DirectoryNotEmptyException. Notice that the base class, IOException, was used to catch exceptions. Within the catch block, a test was made to determine what caused the exception, using the File class' isDirectory method. Once the root cause of the exception was determined, the appropriate exception was thrown. The use of the Files class is detailed in Chapter 4, Managing Files and Directories.

By specifying precisely which exceptions can be thrown by the method, we can be clear about what callers of the method can expect. In addition, it prevents the inadvertent throwing of other IOException derived exceptions from the method. The drawback of this example is that if another exception, such as a FileSystemException, is the root cause, then we will have missed it. It will be caught in the deleteFile method, since it is derived from the IOException. However, we have failed to handle it in the method or pass it to the calling method.

See also

The previous three recipes provide additional coverage of exception handling in Java 7.

 

Using the diamond operator for constructor type inference


The use of the diamond operator simplifies the use of generics when creating an object. It avoids unchecked warnings in a program, and it reduces generic verbosity by not requiring explicit duplicate specification of parameter types. Instead, the compiler infers the type. Dynamically-typed languages do this all the time. While Java is statically typed, the use of the diamond operator allows more inferences than before. There is no difference in the resulting compiled code.

The compiler will infer the parameter types for the constructors. This is an example of the convention over configuration (http://en.wikipedia.org/wiki/Convention_over_configuration). By letting the compiler infer the parameter type (convention), we avoid explicit specification (configuration) of the object. Java also uses annotations in many areas to affect this approach. Type inference is now available, whereas it was only available for methods before.

Getting ready

To use the diamond operator:

  1. 1. Create a generic declaration of an object.

  2. 2. Use the diamond operator,<>, to specify the type inference that is to be used.

How to do it...

  1. 1. Create a simple Java application with a main method. Add the following code example to the main method to see how they work. For example, to declare a java.util.List of strings, we can use the following:

    List<String> list = new ArrayList<>();
    
  2. 2. The identifier, list, is declared as a list of strings. The diamond operator,<>, is used to infer the List type as String. No warnings are generated for this code.

How it works...

When an object is created without specifying the data type, it is called a raw type. For example, the following uses a raw type when instantiating the identifier, list:

List<String> list = new ArrayList(); // Uses raw type

When the code is compiled, the following warnings are generated:

Note: packt\Bin.java uses unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

An unchecked warning is generated. It is generally desirable to eliminate unchecked warnings in an application. When the —Xlint:unchecked is used we get the following:

packt\Bin.java:26: warning: [unchecked] unchecked conversion

List<String> arrayList = new ArrayList();

^

required: List<String>

found: ArrayList

1 warning

Before Java 7, we could address this warning by explicitly using a parameter type as follows:

List<String> list = new ArrayList<String>();

With Java 7, the diamond operator makes this shorter and simpler. This operator becomes even more useful with more complex data types, such as, a List of Map objects as follows:

List<Map<String, List<String>> stringList = new ArrayList<>();

There's more...

There are several other aspects of type inference that should be discussed:

  • Using the diamond operator when the type is not obvious

  • Suppressing unchecked warnings

  • Understanding erasure

Using the diamond operator when the type is not obvious

Type inference is supported in Java 7 and later, only if the parameter type for the constructor is obvious. For example, if we use the diamond operator without specifying a type for the identifier shown as follows, we will get a series of warnings:

List arrayList = new ArrayList<>();
arrayList.add("First");
arrayList.add("Second");

Compiling the program with —Xlint:unchecked, results in the following warnings:

... packt\Bin.java:29: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList

arrayList.add("First");

where E is a type-variable:

E extends Object declared in class ArrayList

... \packt\Bin.java:30: warning: [unchecked] unchecked call to add(E) as a member of the raw type ArrayList

arrayList.add("Second");

where E is a type-variable:

E extends Object declared in class ArrayList

2 warnings

These warnings will go away if the data type is specified as follows:

List<String> arrayList = new ArrayList<>();

Suppressing unchecked warnings

While not necessarily desirable, it is possible to use the @SuppressWarnings annotation to suppress unchecked exceptions generated by the failure to use the diamond operator. The following is an example of this:

@SuppressWarnings("unchecked")
List<String> arrayList = new ArrayList();

Understanding erasure

Erasure occurs when generics are used. The data type used in the declaration is not available at run-time. This language design decision was made when Java 1.5 introduced generics, to make the code backwards compatible.

Consider the following three methods. They differ only in the declaration of the arrayList variable:

private static void useRawType() {
List<String> arrayList = new ArrayList();
arrayList.add("First");
arrayList.add("Second");
System.out.println(arrayList.get(0));
}
private static void useExplicitType() {
List<String> arrayList = new ArrayList<String>();
arrayList.add("First");
arrayList.add("Second");
System.out.println(arrayList.get(0));
}
private static void useImplicitType() {
List<String> arrayList = new ArrayList<>();
arrayList.add("First");
arrayList.add("Second");
System.out.println(arrayList.get(0));
}

When these methods are compiled, the type information available at compile-time is lost. If we examine the compiled bytecode for these three methods, we will find that there is no difference between them.

Using the following command will display the byte codes for the program:

javap -v -p packt/Bin

The generated code is identical for these three methods. The code for the useImplicitType is shown as follows. It is identical to the other two methods;

private static void useImplicitType();
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=3, locals=1, args_size=0
0: new #5 // class java/util/ArrayList
3: dup
4: invokespecial #6 // Method java/util/ArrayList."<in
it>":()V
7: astore_0
8: aload_0
9: ldc #7 // String First
11: invokevirtual #8 // Method java/util/ArrayList.add:
(Ljava/lang/Object;)Z
14: pop
15: aload_0
16: ldc #9 // String Second
18: invokevirtual #8 // Method java/util/ArrayList.add:
(Ljava/lang/Object;)Z
21: pop
22: getstatic #10 // Field java/lang/System.out:Ljav
a/io/PrintStream;
25: aload_0
26: iconst_0
27: invokevirtual #11 // Method java/util/ArrayList.get:
(I)Ljava/lang/Object;
30: checkcast #12 // class java/lang/String
33: invokevirtual #13 // Method java/io/PrintStream.prin
tln:(Ljava/lang/String;)V
36: return
 

Using the @SafeVarargs annotation


The @SafeVarargs and @SuppressWarnings annotations can be used to deal with various warnings that are normally harmless. The @SuppressWarnings annotation, as its name implies, will suppress specific types of warnings.

The @SafeVarargs annotation, introduced in Java 7, is used to designate certain methods and constructors that use a variable number of arguments as safe. Methods can be passed with a variable number of arguments. These arguments may be generics. If they are, then it may be desirable to suppress harmless warnings using the @SafeVarargs annotation.

Getting ready

The @SafeVarargs annotation is used with constructors and methods. To use the @SafeVarargs annotation, the following steps need to be followed:

  1. 1. Create a method or constructor that uses a variable number of generic parameters.

  2. 2. Add the @SafeVarargs annotation before the method declaration.

In Java 7, mandatory compiler warnings are generated with generic variable argument methods or constructors. The use of the @SafeVarargs annotation suppresses warnings, when these methods or constructors are deemed to be harmless.

How to do it...

  1. 1. To demonstrate the @SafeVarargs annotation, create an application with a method called displayElements as follows. The method displays information about each parameter and its value:

    package packt;
    import java.util.ArrayList;
    public class SafeVargExample {
    public static void main(String[] args) {
    }
    @SafeVarargs
    public static <T> void displayElements(T... array) {
    for (T element : array) {
    System.out.println(element.getClass().getName() + ": " + element);
    }
    }
    }
    

    The method uses a variable number of generic parameters. Java implements a variable number of arguments as an array of objects, which only hold reifiable types. A reifiable type is discussed in the How it works section.

  2. 2. Add the following code in the main method to test the method:

    ArrayList<Integer> a1 = new ArrayList<>();
    a1.add(new Integer(1));
    a1.add(2);
    ArrayList<Float> a2 = new ArrayList<>();
    a2.add(new Float(3.0));
    a2.add(new Float(4.0));
    displayElements(a1, a2, 12);
    
  3. 3. Execute the application. The output should appear as follows:

    java.util.ArrayList: [1, 2]

    java.util.ArrayList: [3.0, 4.0]

    java.lang.Integer: 12

  4. 4. Notice the use of the diamond operator,<>, in the declaration of the java.util.ArrayList. This operator is new to Java 7, and is discussed in the recipe: Using the diamond operator for constructor type inference.

How it works...

In Java, a method or constructor with a variable number of arguments is created using the ... notation as used in the displayElements method. In this case, the element type is a generic.

The basic problem is the inability of generics and arrays to play well together. When generics were added to the Java language in 1.5, they were implemented to make them backwards compatible with earlier code. This meant that they were implemented using erasure. That is, any type of information that was available at compile-time was removed at run-time. This data is referred to as non-reifiable.

Arrays are reified. Information about an array's element type is retained and can be used at run-time. Note that it is not possible to declare an array of generics. It is possible to create a simple array of strings as follows:

String arr[] = {"First", "Second"};

However, we cannot create an array of generics, such as the following:

List<String> list1 = new ArrayList<String>();
list1.add("a");
List<String> list2 = new ArrayList<String>();
list2.add("b");
List<String> arr[] = {list1, list2}

This code will generate the following error message:

Cannot create a generic array of List<String>

A method that uses a variable number of arguments is implemented as an array of objects. It can only deal with reifiable types. When a method using a variable number of arguments is invoked, an array is created to hold these parameters.

Since we used a method with variable number of generic arguments, a run-time problem can occur known as heap pollution. Heap pollution occurs when a variable of a parameterized type is assigned a different type than that used to define it. At run-time, this will manifest itself as an unchecked warning. At run-time, it will result in a java.lang.ClassCastException. Use the @SafeVarargs annotation to designate a method as one that avoids heap pollution.

Methods that use a variable number of generic arguments will result in a compile-time warning. However, not all methods that use a variable number of generic arguments will result in a run-time exception. The @SafeVarargs is used to mark the safe methods as safe. If it is possible for a run-time exception to occur, then the annotation should not be used. This is further explored in the next section.

Notice that if the @SafeVarargs annotation was not used then the following warnings will be generated:

warning: [unchecked] unchecked generic array creation for varargs parameter of type ArrayList<? extends INT#1>[]

warning: [unchecked] Possible heap pollution from parameterized vararg type T

The first warning is applied against the displayElements invocation and the second warning is applied against the actual method. There is nothing wrong with the code, so suppression of these warnings is perfectly acceptable.

We could use the @SuppressWarnings("unchecked") annotation instead to suppress the warning at the declaration of the method, but warnings are still generated with their usage. Using @SafeVarargs suppresses warnings at both places.

There's more...

Also of interest is:

  • The use of @SafeVarargs annotation in the Java core libraries

  • An example of heap pollution

The use of @SafeVarargs annotation in Java core libraries

JDK 1.7 libraries have incorporated the @SafeVarargs annotation. These include the following:

  • public static <T> List<T> java.util.Arrays.asList(T... a)

  • public static <T> boolean java.util.Collections.addAll(Collection<? super T> c, T... elements)

  • public static <E extends Enum<E>> java.util.EnumSet<E> EnumSet.of(E first, E... rest)

  • protected final void javax.swing.SwingWorker.publish(V... chunks)

These methods were tagged with the @SafeVarargs annotation to indicate that they will not cause heap pollution. These methods are considered to be safe.

An example of heap pollution

Some methods should not be marked as safe, as illustrated with the following code adapted from the javadoc description of the @SafeVarargs annotation (http://download.oracle.com/javase/7/docs/api/index.html under the java.lang.SafeVarargs annotation documentation).

Add the following method to your code:

@SafeVarargs // Not actually safe!
static void merge(List<String>... stringLists) {
Object[] array = stringLists;
List<Integer> tmpList = Arrays.asList(42);
array[0] = tmpList; // Semantically invalid, but compiles without warnings
String element = stringLists[0].get(0); // runtime ClassCastException
}

Test the method with the following code:

List<String> list1 = new ArrayList<>();
list1.add("One");
list1.add("Two");
list1.add("Three");
List<String> list2 = new ArrayList<>();
list2.add("Four");
list2.add("Five");
list2.add("Six");
merge(list1,list2);

Execute the program. You should get the following error message:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

A list of strings was passed to the method and assigned to the identifier stringList. Next, an array of objects was declared and assigned to the same object referenced by stringList. At this point, the stringList and array referenced the same object, a java.util.List of strings. The following illustrates the configuration of the memory at this point:

With the following assignment:

array[0] = tmpList

The first element of the array is reassigned to tmpList. This reassignment is illustrated in the following figure:

At this point, we have effectively assigned an Integer object to a String reference variable. It has been assigned to the first element of the array referenced by both stringLists and array. The dashed line shows the old reference, which has been replaced with the line. When an attempt is made at run-time to assign this Integer object to a String reference variable, the ClassCastException occurs.

This method results in heap pollution and should not be annotated with @SafeVarargs as it is not safe. The assignment of tmpList to the first element of the array is permitted, since we are simply assigning a List<Integer> object to an Object reference variable. This is an example of upcasting, which is legal in Java.

See also

The previous recipe Using the diamond operator for constructor type inference explains an improvement in the use of generics.

About the Authors

  • Richard M. Reese

    Richard M. Reese has worked in both industry and academia. For 17 years, he worked in the telephone and aerospace industries, serving in several capacities, including research and development, software development, supervision, and training. He currently teaches at Tarleton State University, where he has the opportunity to apply his years of industry experience to enhance his teaching. Richard has written several Java books and a C pointer book. He uses a concise and easy-to-follow approach to the topics at hand. His Java books have addressed EJB 3.1, updates to Java 7 and 8, certification, jMonkeyEngine, natural language processing, functional programming, networks, and data science.

    Browse publications by this author
  • Jennifer L. Reese

    Jennifer L. Reese studied computer science at Tarleton State University. She also earned her M.Ed. from Tarleton in December 2016. She currently teaches computer science to high-school students. Her research interests include the integration of computer science concepts with other academic disciplines, increasing diversity in computer science courses, and the application of data science to the field of education. She previously worked as a software engineer developing software for county- and district-level government offices throughout Texas. In her free time she enjoys reading, cooking, and traveling—especially to any destination with a beach. She is a musician and appreciates a variety of musical genres.

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Access now