Hiển thị các bài đăng có nhãn Java SE 7. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Java SE 7. Hiển thị tất cả bài đăng

Thứ Năm, 24 tháng 1, 2013

JavaFX 2 XYCharts and Java 7 Features

One of my favorite features of JavaFX 2 is the standard charts it provides in its javafx.scene.chart package. This package provides several different types of charts out-of-the-box. All but one of these (the PieChart) are "2 axis charts" (specific implementations of the XYChart). In this post, I look at the commonality between these specializations of XYChart. Along the way, I look at several Java 7 features that come in handy.

A UML class diagram for key chart types in the javafx.scene.chart package is shown next. Note that AreaChart, StackedAreaChart, BarChart, StackedBarChart, BubbleChart, LineChart, and ScatterChart all extend XYChart.

As the UML diagram above (generated using JDeveloper) indicates, the PieChart extends Chart directly while all the other chart types extend XYChart. Because all the chart types other than PieChart extend XYChart, they share some common features. For example, they are all 2-axis charts with a horizontal ("x") axis and a vertical ("y") axis. They generally allow data to be specified in the same format (data structure) for all the XY charts. The remainder of this post demonstrates being able to use the same data for most of the XYCharts.

The primary use of a chart is to show data, so the next code listing indicates retrieving of data from the 'hr' sample schema in an Oracle database. Note that JDBC_URL, USERNAME, PASSWORD, and AVG_SALARIES_PER_DEPARTMENT_QUERY are constant Strings used in the JDBC connection and for the query.

getAverageDepartmentsSalaries()

/**
* Provide average salary per department name.
*
* @return Map of department names to average salary per department.
*/
public Map<String, Double> getAverageDepartmentsSalaries()
{
final Map<String, Double> averageSalaryPerDepartment = new HashMap<>();
try (final Connection connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD);
final Statement statement = connection.createStatement();
final ResultSet rs = statement.executeQuery(AVG_SALARIES_PER_DEPARTMENT_QUERY))
{
while (rs.next())
{
final String departmentName = rs.getString(COLUMN_DEPARTMENT_NAME);
final Double salaryAverage = rs.getDouble(ALIAS_AVERAGE_SALARY);
averageSalaryPerDepartment.put(departmentName, salaryAverage);
}
}
catch (SQLException sqlEx)
{
LOGGER.log(
Level.SEVERE,
"Unable to get average salaries per department - {0}", sqlEx.toString());
}
return averageSalaryPerDepartment;
}

The Java code snippet above uses JDBC to retrieve data for populating a Map of department name Strings to the average salary of the employees in each department. There are a couple of handy Java 7 features used in this code. A small feature is the inferred generic parameterized typing of the diamond operator used with the declaration of the local variable averageSalaryPerDepartment (line 8). This is a small granule of syntax sugar, but it does make the code more concise.

A more significant Java 7 feature is use of try-with-resources statement for the handling of the Connection, Statement, and ResultSet resources (lines 9-11). This is a much nicer way to handle the opening and closing of these resources, even in the face of exceptions, than was previously necessary when using JDBC. The Java Tutorials page on The try-with-resources Statement advertises that this statement "ensures that each resource is closed at the end of the statement" and that each resource will "be closed regardless of whether the try statement completes normally or abruptly." The page also notes that when there are multiple resources specified in the same statement as is done in the above code, "the close methods of resources are called in the opposite order of their creation."

The data retrieved from the database can be placed into the appropriate data structure to support use by most of the XYCharts. This is shown in the next method.

ChartMaker.createXyChartDataForAverageDepartmentSalary(Map)

/**
* Create XYChart Data representing average salary per department name.
*
* @param newAverageSalariesPerDepartment Map of department name (keys) to
* average salary for each department (values).
* @return XYChart Data representing average salary per department.
*/
public static ObservableList<XYChart.Series<String, Double>> createXyChartDataForAverageDepartmentSalary(
final Map<String, Double> newAverageSalariesPerDepartment)
{
final Series<String, Double> series = new Series<>();
series.setName("Departments");
for (final Map.Entry<String, Double> entry : newAverageSalariesPerDepartment.entrySet())
{
series.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue()));
}
final ObservableList<XYChart.Series<String, Double>> chartData =
FXCollections.observableArrayList();

chartData.add(series);
return chartData;
}

The method just shown places the retrieved data in a data structure that can be used by nearly all of the XYChart-based charts. With the retrieved data now packaged in a JavaFX observable collection, the charts can be easily generated. The next code snippet shows methods for generating several XYChart-based charts (Area, Bar, Bubble, Line, and Scatter). Note how similar they all are and how the use the same data provided by the same method. The StackedBar and StackedArea charts can also use similar data, but are not shown here because they are not interesting for the single series of data being used in this example.

Methods for Generating XYCharts Except BubbleChart and Stacked Charts

private XYChart<String, Double> generateAreaChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final AreaChart<String, Double> areaChart =
new AreaChart<>(
xAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalary(
this.databaseAccess.getAverageDepartmentsSalaries()));
return areaChart;
}

private XYChart<String, Double> generateBarChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final BarChart<String, Double> barChart =
new BarChart<>(
xAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalary(
this.databaseAccess.getAverageDepartmentsSalaries()));
return barChart;
}

private XYChart<Number, Number> generateBubbleChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final Axis<Number> deptIdXAxis = new NumberAxis();
deptIdXAxis.setLabel("Department ID");
final BubbleChart<Number, Number> bubbleChart =
new BubbleChart(
deptIdXAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalaryById(
this.databaseAccess.getAverageDepartmentsSalariesById()));
return bubbleChart;
}

private XYChart<String, Double> generateLineChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final LineChart<String, Double> lineChart =
new LineChart<>(
xAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalary(
this.databaseAccess.getAverageDepartmentsSalaries()));
return lineChart;
}

private XYChart<String, Double> generateScatterChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final ScatterChart<String, Double> scatterChart =
new ScatterChart<>(
xAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalary(
this.databaseAccess.getAverageDepartmentsSalaries()));
return scatterChart;
}

These methods are so similar that I could have actually used method handles (or more traditional reflection APIs) to reflectively call the appropriate chart constructor rather than use separate methods. However, I am using these for my RMOUG Training Days 2013 presentation in February and so wanted to leave the chart-specific constructors in place to make them clearer to audience members.

One exception to the general handling of XYChart types is the handling of BubbleChart. This chart expects a numeric type for its x-axis and so the String-based (department name) x-axis data provided above will not work. A different method (not shown here) provides a query that returns average salaries by department ID (Long) rather than by department name. The slightly different generateBubbleChart method is shown next.

generateBubbleChart(Axis, Axis)

private XYChart<Number, Number> generateBubbleChart(
final Axis<String> xAxis, final Axis<Double> yAxis)
{
final Axis<Number> deptIdXAxis = new NumberAxis();
deptIdXAxis.setLabel("Department ID");
final BubbleChart<Number, Number> bubbleChart =
new BubbleChart(
deptIdXAxis, yAxis,
ChartMaker.createXyChartDataForAverageDepartmentSalaryById(
this.databaseAccess.getAverageDepartmentsSalariesById()));
return bubbleChart;
}

Code could be written to call each of these different chart generation methods directly, but this provides a good chance to use Java 7's method handles. The next code snippet shows this being done. Not only does this code demonstrate Method Handles, but it also uses Java 7's multi-catch exception handling mechanism (line 77).


/**
* Generate JavaFX XYChart-based chart.
*
* @param chartChoice Choice of chart to be generated.
* @return JavaFX XYChart-based chart; may be null.
* @throws IllegalArgumentException Thrown if the provided parameter is null.
*/
private XYChart<String, Double> generateChart(final ChartTypes chartChoice)
{
XYChart<String, Double> chart = null;
final Axis<String> xAxis = new CategoryAxis();
xAxis.setLabel("Department Name");
final Axis<? extends Number> yAxis = new NumberAxis();
yAxis.setLabel("Average Salary");
if (chartChoice == null)
{
throw new IllegalArgumentException(
"Provided chart type was null; chart type must be specified.");
}
else if (!chartChoice.isXyChart())
{
LOGGER.log(
Level.INFO,
"Chart Choice {0} {1} an XYChart.",
new Object[]{chartChoice.name(), chartChoice.isXyChart() ? "IS" : "is NOT"});
}

final MethodHandle methodHandle = buildAppropriateMethodHandle(chartChoice);
try
{
chart =
methodHandle != null
? (XYChart<String, Double>) methodHandle.invokeExact(this, xAxis, yAxis)
: null;
chart.setTitle("Average Department Salaries");
}
catch (WrongMethodTypeException wmtEx)
{
LOGGER.log(
Level.SEVERE,
"Unable to invoke method because it is wrong type - {0}",
wmtEx.toString());
}
catch (Throwable throwable)
{
LOGGER.log(
Level.SEVERE,
"Underlying method threw a Throwable - {0}",
throwable.toString());
}

return chart;
}

/**
* Build a MethodHandle for calling the appropriate chart generation method
* based on the provided ChartTypes choice of chart.
*
* @param chartChoice ChartTypes instance indicating which type of chart
* is to be generated so that an appropriately named method can be invoked
* for generation of that chart.
* @return MethodHandle for invoking chart generation.
*/
private MethodHandle buildAppropriateMethodHandle(final ChartTypes chartChoice)
{
MethodHandle methodHandle = null;
final MethodType methodDescription =
MethodType.methodType(XYChart.class, Axis.class, Axis.class);
final String methodName = "generate" + chartChoice.getChartTypeName() + "Chart";

try
{
methodHandle =
MethodHandles.lookup().findVirtual(
this.getClass(), methodName, methodDescription);
}
catch (NoSuchMethodException | IllegalAccessException exception)
{
LOGGER.log(
Level.SEVERE,
"Unable to acquire MethodHandle to method {0} - {1}",
new Object[]{methodName, exception.toString()});
}
return methodHandle;
}

A series of images follows that shows how these XY Charts appear when rendered by JavaFX.

Area Chart
Bar Chart
Bubble Chart
Line Chart
Scatter Chart

As stated above, Method Handles could have been used to reduce the code even further because individual methods for generating each XYChart are not absolutely necessary and could have been reflectively called based on desired chart type. It's also worth emphasizing that if the x-axis data had been numeric, the code would be the same (and could be reflectively called) for all XYChart types including the Bubble Chart.

JavaFX makes it easy to generate attractive charts representing provided data. Java 7 features make this even easier by making code more concise and more expressive and allowing for easy application of reflection when appropriate.

Thứ Sáu, 18 tháng 1, 2013

Java Zero Day Vulnerability Exploits JMX and MethodHandles

I recently identified software security issues (#2), especially related to Java, as one of the most significant software development themes of 2012. Not even a month into 2013, a news story receiving a lot of press is the U.S. Department of Homeland Security's issuing of Alert (TA13-010A), which is described with more technical details in Vulnerability Note VU#625617. Oracle has since released a Security Alert for CVE-2013-0422.

Vulnerability Note VU#625617 includes a paragraph that is particularly insightful:

By leveraging the a vulnerability in the Java Management Extensions (JMX) MBean components, unprivileged Java code can access restricted classes. By using that vulnerability in conjunction with a second vulnerability involving recursive use of the Reflection API via the invokeWithArguments method of the MethodHandle class, an untrusted Java applet can escalate its privileges by calling the the setSecurityManager() function to allow full privileges, without requiring code signing. Oracle Java 7 update 10 and earlier Java 7 versions are affected. OpenJDK 7, and subsequently IcedTea, are also affected. The invokeWithArguments method was introduced with Java 7, so therefore Java 6 is not affected.

The above scenario is described in great detail in Tim Boudreau's excellent The Java Security Exploit in (Mostly) Plain English and he references Java 0day 1.7.0_10 decrypted source code that demonstrates the code that can implement an attack that takes advantage of the described JMX/MethodHandles combination vulnerability. Kafeine's (Malware don't need Coffee) post 0 day 1.7u10 (CVE-2013-0422) spotted in the Wild - Disable Java Plugin NOW ! provides numerous screen snapshots to illustrate this Java Zero-Day Malware in action.

The TA13-010A/CVE-2013-0422 Java Zero Day Vulnerability has made the mainstream news with coverage by Norton/Symantec (What's All the Buzz About Java? Fixing The Vulnerability and Java Zero-Day Dished Up from Cool Exploit Kit), McAfee (Java Zero-Day Vulnerability Pushes Out Crimeware), InformationWeek (Java Zero Day Attack: Second Bug Found), Fox News (Reuters: As Hacking Concerns Build, U.S. Warns on Java Software), CNN (Critical Java vulnerability due to incomplete earlier patch), and many more news outlets.

As stated above, Oracle has issued a patch, but the Department of Homeland Security still recommends disabling Java in the browser.

Thứ Sáu, 11 tháng 1, 2013

Portable Logger Names with Java 7 Method Handles

Java 7 introduced the Method Handles with the java.lang.invoke.MethodHandle and java.lang.invoke.MethodHandles classes. The Well-Grounded Java Developer (which I have previously reviewed) covers method handles in Chapter 5 (Section 5.2) and concludes with a trivial but highly useful example of what one can do with method handles and logger naming. I briefly explain this idea in this blog post.

When acquiring a logger for a particular Java class, it is common for the Java developer to use that very class to name the logger. In Log4j, this is typically done with a reference to the class itself. For java.util.logging, this is typically done with a reference to the fully qualified name of the class. Although this is easy to do, it is possible to mistakenly provide the wrong class, especially when the incorrectly provided class is in the same package and a logger definition statement is copied and pasted from an existing class to a new class. As the authors of The Well-Grounded Java Developer suggest, the newly introduced MethodHandles class can make this declaration more portable and always based contextually on the class in which the declaration resides.

The MethodHandes.lookup() method returns an instance of MethodHandles.Lookup, from which the lookupClass() method can be invoked. This latter method's return value can be used directly in naming the Log4j logger or can have that returned Class's getCanonicalName() method return its name as a String for naming the java.util.logging logger.

The following two code snippets show this for a class specifying its Log4j logger and for a class specifying its java.util.logging logger. Note that there are more characters in these examples than might normally be present when hard-coding the class or class name into the logger declaration, but this code ensures that the actual class or class name is always used.

MethodHandles Approach to Naming log4j Logger

package dustin.examples.methodhandles;

import java.lang.invoke.MethodHandles;
import org.apache.log4j.Logger;

/**
* Demonstrating use of MethodHandles with Log4j.
*
* @author Dustin
*/
public class MethodHandlesLoggerLog4j
{
/** Use Java 7 MethodHandles to get my class for logger. */
private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass());

public static void main(final String[] arguments)
{
final String msg = "Hello World: Using MethodHandles for Class to associate with Log4j logger.";
LOGGER.info(msg);
}
}
MethodHandles Approach to Naming java.util.logging Logger

package dustin.examples.methodhandles;

import java.lang.invoke.MethodHandles;
import java.util.logging.Logger;

/**
* Demonstrating use of MethodHandles with java.util.logging.
*
* @author Dustin
*/
public class MethodHandlesLoggerJavaUtilLogging
{
/** Use Java 7 MethodHandles to get my class name for logger. */
private static final Logger LOGGER =
Logger.getLogger(MethodHandles.lookup().lookupClass().getCanonicalName());

public static void main(final String[] arguments)
{
final String msg = "Hello World: Using MethodHandles for Class to associate with java.util.logging logger.";
LOGGER.info(msg);
}
}

This post has looked at an idea for a very simple use of the newly available Java 7 MethodHandles class as covered in The Well-Grounded Java Developer. Although this is a small thing, it is illustrative of a convenient use of a lesser advertised Java 7 language feature that provides many more and far more powerful (and more complex) uses.

Thứ Năm, 4 tháng 10, 2012

JavaOne 2012: Diagnosing Your Application on the JVM

It was worth attending Staffan Larsen's (Oracle Java Serviceability Architect) presentation "Diagnosing Your Application on the JVM" (Hilton Plaza A/B) just for learning of the new jcmd command-line tool provided with Oracle's JVM 7. The rest of the presentation was "bonus" for me, which was nice for the last session I attended on Wednesday of JavaOne 2012.

The Oracle HotSpot JDK provides jcmd, a command-line tool designed to be both backwards compatible and forward adaptable for future versions of Java. It is designed to support new tools and features that come with new SDKs in a standardized approach. The following screen snapshot shows it used for most basic jps-like functionality (Larsen mentioned jps almost as briefly as I just did and referred to jcmd as "like jps but more powerful").

As the above image shows, jcmd can be used like jps.

Larsen showed some handy features of the jcmd command. He had some small sample Java applications that helped him to demonstrate jcmd. For my purposes, I'm running jconsole in one terminal on my machine and then I'll run jcmd commands against that JVM in which jconsole is running. The next screen snapshot shows how the basic (no arguments) jcmd call provides information on that JConsole process.

jcmd supports execution against JVM processes either by process ID (pid) or by process name. The next screen snapshot shows running jcmd against the JConsole process by that name and passing it help to see which options can be run against that particular process. Note that I tried unsuccessfully to run this against 'dustin' (no existing process) to prove that jcmd is really showing options available for running processes.

The feature demonstrated in the last screen snapshot is one of the most compelling reasons for moving from existing command-line tools provided with the Oracle JDK to jcmd. This image shows how jcmd can provide a list of the available options on a per process basis, allowing for ultimate flexibility in terms of supporting past versions or future versions of Java that support different/new commands.

Just as jcmd <pid> help (or replace pid with process name) lists the available operations that can be run by jcmd against a particular JVM process, this same help mechanism can be run against any one of those specific listed commands [with syntax jcmd <pid> <command_name> help (or use process name instead of pid)], though I could not get this to work properly on my Windows machine.

The next image shows actually running that command against that JVM process rather than simply asking for help on it.

In the two screen snapshots immediately above, I ran jcmd against the pid instead of the process name simply to show that it works against both process ID as well as name. The next screen snapshot shows executing jcmd against the JVM process to get VM flags and command-line options from the JVM process (the pid of this instance of JConsole process is 3556).

Running jcmd's Thread.print command against a supporting JVM process makes easy work of viewing the targeted JVM's threads. The following output is generated from running jcmd JConsole Thread.print against my running JConsole process.


3556:
2012-10-04 23:39:36
Full thread dump Java HotSpot(TM) Client VM (23.2-b09 mixed mode, sharing):

"TimerQueue" daemon prio=6 tid=0x024bf000 nid=0x1194 waiting on condition [0x069af000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x23cf2db0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:209)
at javax.swing.TimerQueue.run(TimerQueue.java:171)
at java.lang.Thread.run(Thread.java:722)

"DestroyJavaVM" prio=6 tid=0x024be400 nid=0x1460 waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE

"AWT-EventQueue-0" prio=6 tid=0x024bdc00 nid=0x169c waiting on condition [0x0525f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x291a90b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.awt.EventQueue.getNextEvent(EventQueue.java:521)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:213)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

"Thread-2" prio=6 tid=0x024bd800 nid=0x4a8 in Object.wait() [0x04bef000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x2917ed80> (a java.io.PipedInputStream)
at java.io.PipedInputStream.read(PipedInputStream.java:327)
- locked <0x2917ed80> (a java.io.PipedInputStream)
at java.io.PipedInputStream.read(PipedInputStream.java:378)
- locked <0x2917ed80> (a java.io.PipedInputStream)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x29184e28> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x29184e28> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at sun.tools.jconsole.OutputViewer$PipeListener.run(OutputViewer.java:109)

"Thread-1" prio=6 tid=0x024bd000 nid=0x17dc in Object.wait() [0x047af000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x29184ee8> (a java.io.PipedInputStream)
at java.io.PipedInputStream.read(PipedInputStream.java:327)
- locked <0x29184ee8> (a java.io.PipedInputStream)
at java.io.PipedInputStream.read(PipedInputStream.java:378)
- locked <0x29184ee8> (a java.io.PipedInputStream)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x2918af80> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x2918af80> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at sun.tools.jconsole.OutputViewer$PipeListener.run(OutputViewer.java:109)

"AWT-Windows" daemon prio=6 tid=0x024bc800 nid=0x16e4 runnable [0x0491f000]
java.lang.Thread.State: RUNNABLE
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:299)
at java.lang.Thread.run(Thread.java:722)

"AWT-Shutdown" prio=6 tid=0x024bc400 nid=0x157c in Object.wait() [0x04c6f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x2918b098> (a java.lang.Object)
at java.lang.Object.wait(Object.java:503)
at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:287)
- locked <0x2918b098> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:722)

"Java2D Disposer" daemon prio=10 tid=0x024bbc00 nid=0x3b8 in Object.wait() [0x0482f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x2918b128> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x2918b128> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at sun.java2d.Disposer.run(Disposer.java:145)
at java.lang.Thread.run(Thread.java:722)

"Service Thread" daemon prio=6 tid=0x024bb800 nid=0x1260 runnable [0x00000000]
java.lang.Thread.State: RUNNABLE

"C1 CompilerThread0" daemon prio=10 tid=0x024c6400 nid=0x120c waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x024bb000 nid=0x1278 waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x024bac00 nid=0xe3c runnable [0x00000000]
java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x024a9c00 nid=0x15c4 in Object.wait() [0x046df000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x2918b358> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x2918b358> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

"Reference Handler" daemon prio=10 tid=0x024a4c00 nid=0xe40 in Object.wait() [0x0475f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x2917e9c0> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x2917e9c0> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x024a3800 nid=0x164c runnable

"VM Periodic Task Thread" prio=10 tid=0x024e7c00 nid=0xcf0 waiting on condition

JNI global references: 563

Larsen showed how to use thread information provided by jcmd to resolve a deadlock.

Larsen showed getting a class histogram from the running JVM process with jcmd. This is done using the command jcmd <pid> GC.class_histogram. A very small subset of its output is shown next (the pid of this JConsole process is 4080 this time).


4080:

num #instances #bytes class name
----------------------------------------------
1: 1730 3022728 [I
2: 5579 638168
3: 5579 447072
4: 645 340288
5: 4030 337448 [C
6: 645 317472
7: 602 218704
8: 942 167280 [B
9: 826 97720 java.lang.Class
10: 3662 87888 java.lang.String
11: 2486 79552 javax.swing.text.html.parser.ContentModel
12: 3220 77280 java.util.Hashtable$Entry
13: 1180 67168 [S
14: 2503 60072 java.util.HashMap$Entry
15: 181 59368
16: 971 43584 [Ljava.lang.Object;
17: 1053 41160 [[I
18: 206 29040 [Ljava.util.HashMap$Entry;
19: 111 27880 [Ljava.util.Hashtable$Entry;
20: 781 18744 java.util.concurrent.ConcurrentHashMap$HashEntry
21: 1069 17104 java.lang.Integer
22: 213 9816 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
23: 202 9696 java.util.HashMap
24: 201 9280 [Ljava.lang.String;
25: 24 8416 [[I

Larsen also demonstrated jstat and several of its useful functions. He demonstrated use of jstat -gcnew (new generation behavior), jstat -precompilation (compilation method statistics), and jstat -options (displays options).

During the course of his presentation, Larsen needed to convert a decimal number (pid?) to its hexadecimal representation for comparing it to the output of another tool. He used the handy printf "%x\n" <pid> command to get the hexadecimal representation of the pid.

Larsen demonstrated use of VisualVM to compare two heap dumps and browse a heap dump. He also demonstrated the VisualVM Profiler.

Larsen moved from the tools previously covered aimed at running JVMs to tools that can be used to analyze JVM core files. He returned to jstack to analyze contents of the core file.

Larsen talked about remotely accessing JVM information via JMX and tools like jconsole and jvisualvm. He demonstrated that jcmd can be used to start JMX exposure as well: ManagementServer.start "with a bunch of parameters." Larsen feels that VisualVM and JConsole would use ManagementServer.start rather than Attach API if implemented today.

jstat can also connect to daemon remotely through use of jstatd. There is no encryption or authentication with jstatd.

jps and jcmd find what's running on system using "well-known file for each JVM": /hsperfdata_<user>/<pod> This file is created on JVM startup and deleted on JVM shutdown. Unused previous files are deleted on startup, so jps and jcmd, as Java programs themselves, will clean these old ones up.

The Attach API "allows sending 'commands' for executionin the JVM," but only works on local machine and for current/same user. This is what jcmd and jstack use. Larsen then went onto explain the different mechanics of using the Attach API for Linux/BSD/Solaris (uses temporary file creation) versus Windows (uses code injection). I employed the Attach API in my post Groovy, JMX, and the Attach API.

Diagnostic commands are "helper routines inside the JVM" that produce "text output." They can be executed via the jcmd utility (and soon via JMX). They each have a self-describing facility: jcmd PerfCounter.print to see the raw contents.

Larsen showed an informative table comparing "communicating with the JVM" approaches: attach, jvmstat, JMX, jstatd, and Serviceability Agent (SA). The SA "should be used as a last resort ('typically for a JVM that is hung')" and uses a "debugger to read information."

Larsen transitioned to talk of future tools. He started this portion of the presentation with coverage of Java Flight Recorder. Java Flight Recorder is a "JVM-built-in profiler and tracer" with "low overhead" and is "always on." Other coming tools are Java Mission Control ("graphical tool providing very detailed runtime monitoring details"), more diagnostic commands for jcmd ("eventually replacing jstack, jmap, jinfo" for various reasons), JMX 2.0 ("something we're picking up again; it was started a very long time ago"), improved logging for JVM (JVM Enhancement Proposal [JEP] 158), and Java Discovery Protocol (anticipating forthcoming JEP for this).

One question asked was if one could see MBeans in VisualVM as can be done in JConsole. As I've blogged on, there is a VisualVM plug-in for doing just that.

Although I felt somewhat comfortable with the Oracle HotSpot JDK command line tools, I was unfamiliar with jcmd and appreciated Larsen's coverage of it. I learned some other things along the way as well. My only complaint is that Larsen's presentation (especially the demonstration) was so rapid fire and so content-rich that I wish I could see it again.

A related (but older) presentation with some of the same content is available at http://www.oracle.com/javaone/lad-en/session-presentations/corejava/22260-enok-1439100.pdf

Thứ Năm, 16 tháng 8, 2012

Recent Java News - Mid-August 2012

Oracle has released significant announcements regarding Java in recent weeks. I summarize some of these in this post.

Java SE 6 End of Life Extended to 2013

Henrik Stahl announced in the post Java 6 End of Public Updates extended to February 2013 that "the Oracle JDK 6 End of Public Updates will be extended through February, 2013." As Stahl states in that post, this is additional time beyond the previously announced extension from July 2012 to November 2012. The Oracle Java SE Support Roadmap has been updated to reflect this new extension.

Java SE 7 Update 6 Released

The 14 August 2012 Oracle Press Release titled Oracle Releases New Java Updates - Java SE 7 Update 6, JavaFX 2.2 and JavaFX Scene Builder 1.0 announces the release of Java SE 7 Update 6 bundled with JavaFX 2.2.

The Java 6 Update 7 Release Notes list the significant new features of this release: JDK and JRE Support for Mac OS X, JDK for Linux on ARM, JavaFX SDK and JavaFX Runtime included in JDK 7u6 and JRE 7u6, Java Access Bridge included in JRE 7u6, Alternative Hash Function, and Changes to Security Warning Dialog Box for Trusted Signed and Self Signed Applications.

JavaOne 2012 Schedule Builder Goes Live

Tori Wieldt's post JavaOne Schedule Builder Live announces that Schedule Builder is now live and available for registered JavaOne 2012 attendees.

Oracle and Fortress

Although not technically Java-related, I found it interesting to read that Oracle is throwing in the towel on development of the Fortran-inspired programming language Fortress.

Thứ Hai, 9 tháng 7, 2012

Book Review: The Well-Grounded Java Developer

Java-related books are perhaps the most widely available books in terms of diverse selections of any programming language. Even so, most Java books seem to fall into one of two categories: they are either introductory/general level books or they are highly focused specific books. These books all have their place and many of them have been beneficial to me in my career, but I'm always on the look out for that rare combination of the two: the book that is relatively general in terms of Java coverage, but is more advanced or looks at the topic quite differently than an introductory or typical general Java book. Books such as Effective Java and Java: The Good Parts come to mind as books that strive to hit this sweet spot. In this book review, I look at soon-to-be-released (in print, with electronic version available already) The Well-Grounded Java Developer, a book whose topic selection has interested me since first hearing about it in early 2011.

The initial paragraph of the "About This Book" section summarizes the authors' intent:

Welcome to The Well-Grounded Java Developer. This book is aimed at turning you into a Java developer for the modern age, reigniting your passion for both the language and platform. Along the way, you’ll discover new Java 7 features, ensure that you’re familiar with essential modern software techniques (such as dependency injection, testdriven development, and continuous integration), and start to explore the brave new world of non-Java languages on the JVM.

The authors of The Well-Grounded Java Developer, Ben Evans and Martijn Verburg, are instrumental players in the London Java Community, a member of the Java SE/EE Executive Committee in the Java Community Process. Both also speak at Java-related conferences with Martijn being well-known as the Diabolical Developer and Ben Evans as "the voice of reason?"

The title of the book and the selection of topics are what appealed to me most about the advertised content of The Well-Grounded Java Developer when I first saw its Table of Contents in the early MEAP edition. The chosen topics seem appropriate for experienced Java developers who are too busy developing solutions for their customers to spend time trying out features of Java 7, delving deeply into the intricacies of Java and the JVM, or playing with the major alternative JVM languages. I have worked with many solid Java developers who are great at Java, but don't have the time or inclination to play with the latest versions of Java or with JVM languages other than Java until or unless they need to for their job role. This book is a perfect quick introduction to these topics for such developers. A single book provides the highlights of Java SE 7 along with introduction material related to the three most popular non-Java JVM languages. It also throws in in-depth coverage of some advanced topics for making good Java developers better. In addition, the book includes information on modern Java development tools.

The Well-Grounded Java Developer is divided into four multi-chapter parts along with five appendices. Part 1 ("Developing with Java 7") introduces new features of Java SE 7 with focus on Project Coin (Chapter 1) and NIO.2 (Chapter 2).

Part 1 : Java 7

Chapter 1 ("Introducing Java 7") briefly discusses Java the language and Java the platform along with other general characteristics of the Java programming language (open source now, compiled or interpreted nature, etc.). The remainder of the first chapter covers various Project Coin features including switching on String, enhanced numeric literal syntax, improved exception handling, try-with-resources (automatic resource management), diamond operator syntax, and simplified variable arguments.

Chapter 2 ("New I/O") provides brief overview and history of NIO in Java before delving into details of Java 7's NIO.2. The chapter introduces NIO.2 via the all-important Path interface and looks at how this new interface enables improved file input/output (with Files class and other handy new files handling mechanisms).

Part 2 : Vital Techniques

Part 2 ("Vital Techniques") of The Well-Grounded Java Developer continues covering new Java 7 features, but the focus is shifted from the first part. In the first part, the focus was on the features new to Java 7. In the second part, other features new to Java 7 are covered, but in this part they are covered as a means to a different end than simply introducing new Java 7 features. The intent of this second part is to provide more in-depth coverage of "vital techniques" that Java developers should know. As the introduction to this part states, it is about "exploring vital programming knowledge and techniques with Java." These "vital techniques" are dependency injection (Chapter 3), concurrency (Chapter 4), class files and bytecode (Chapter 5), and performance tuning (Chapter 6).

Although there are great books devoted to some of these topics covered in Part 2 (Java Concurrency in Practice and Java Performance for example), many Java developers don't have the time, interest, or inclination to purchase and read these books. These chapters help to get a Java developer going with these ideas and more comprehensive books can be referenced when more comfortable with the subject or when more details are needed.

Chapter 3 ("Dependency Injection") provides an introduction to dependency injection (DI) and contrasts it with the encompassing concept of inversion of control (IoC). The chapter introduces JSR 330 ("Dependency Injection for Java") and discusses using Google Guice as an implementation of JSR 330.

The introduction to Chapter 4 ("Modern Concurrency") includes this description of the intent of the chapter:

The aim of this chapter is to make you aware of the underlying platform mechanisms that explain why Java’s concurrency works the way it does. We’ll also cover enough general concurrency theory to give you the vocabulary to understand the issues involved, and to teach you about both the necessity and the difficulty involved in getting concurrency right.

Chapter 5 ("Class Files and Bytecode") is one of the book's chapters that I think can be of most value to the highest percentage of intermediate to advanced Java developers. Classloading is one of the most frustrating issues in Java development and the fifth chapter attacks that topic head-on. A feature new to Java 7, method handles, are then covered. Method handles are described in this chapter as the "new Java 7 way to achieve the same ends [as the Java Reflection API], with much cleaner code."

When I reviewed the book Java Reflection in Action, I noted that one of its few weaknesses was its age (2004/JDK 1.4) and I concluded that "the most glaring omission from a book on Java reflection is Java 7's introduction of method handles, but few Java books in print today cover these." The Well-Grounded Java Developer is a welcome exception to this statement with an entire section (5.2) devoted to the topic.

I've been a big fan of the javap tool ("Java Class File Disassembler") that comes with the HotSpot SDK, but one of the things that has made it more difficult to learn to use that tool effectively is lack of easily accessible documentation on it. Section 5.3 ("Examining Class Files") of the fifth chapter goes a long way toward remedying that deficiency. Besides introducing javap, the ambitious 5.3 section also covers reading bytecode. This chapter is dense with detail, but this is welcome detail and a great introduction to the subject.

The final section of Chapter 5 (Section 5.5 on "invokedynamic") introduces Java 7's invokedynamic. The introduction to the section notes where this subject likely likes in terms of interest to general Java developers:

[invokedynamic] isn’t a feature that will necessarily be used directly by every working developer, because it involves a very advanced use case. This feature is for frameworks developers and non-Java languages at present.

Chapter 6 ("Understanding Performance Tuning") introduces Java and JVM performance tuning by reminding the reader that performance tuning is often not necessary and depends on measurement with realistic loads. The chapter provides definitions of performance-related terminology and introduces "a pragmatic approach to performance analysis." This sixth chapter also discusses the garbage collection in more details than most Java developers are probably aware of and introduces some of the Oracle (HotSpot) JVM options that can be used.

Chapter 6 also introduces another Oracle JVM command-line tool (jmap) ["Memory Map"] and provides descriptive text on how to read jmap's output (similar to approach used with javap coverage in Chapter 5).

Part 3 : Alternative JVM Languages

Part 3 ("Polyglot Programming on the JVM") moves beyond the Java programming language and focuses on alternative languages running on the JVM. The authors point out that learning about these alternative JVM languages can be useful to Java developers because "many of the new ideas that will be needed in the future are present in other JVM languages today." I'll also add that, at least in the case of Groovy, I've found it useful already for things where Java is not as strong (scripting).

Chapter 7 ("Alternative JVM Languages") introduces this third part of the book focused on alternative JVM languages. This chapter covers why one would be interested in an alternative JVM language before delving into how alternative JVM languages can be used to support functional programming concepts on the JVM. The chapter outlines different ways to classify non-Java JVM languages such as interpreted versus compiled, statically typed versus dynamically typed, and imperative versus functional. The chapter also contrasts completely new languages designed for the JVM (Groovy, Scala, Clojure) with "reimplementation" languages (pre-existing languages ported to the JVM such as Jython, JRuby, and Rhino).

Chapter 7 provides information on how to decide which alternative JVM language to choose for different situations. The authors quickly introduce the non-Java JVM languages that each get a chapter's focus (Groovy, Scala, and Clojure) and explain why they selected these languages upon which to focus.

We’ve picked three languages that we see having the greatest potential longevity and influence. These are the languages on the JVM (Groovy, Scala, and Clojure) that already have well-established mind share among polyglot programmers.

After Chapter 7 kicks off Part 3 on polygot programming on the JVM, the next three chapters of Part 3 each focus on a specific alternative JVM language: Chapter 8 ("Groovy: Java’s dynamic friend"), Chapter 9 ("Scala: powerful and concise"), and Chapter 10 ("Clojure: safer programming"). Each of these three chapters provides an overview of the respective alternative JVM languages. Of course, a single chapter is not sufficient to comprehensively introduce a programming language, so these chapters focus on the strengths of each covered language. They also cover things such as Java interoperability (for Groovy and Clojure) and use contrasting of the languages with Java to illustrate language features.

Part 4 : Applying Alternative Language and New Java Techniques and Tools

Part 4 ("Crafting the Polyglot Project") applies information covered earlier in the book to "some of the most common and important techniques in modern software development." Three of the four chapters in this part look at modern software development techniques (test-driven development, building/continuous integration, and rapid web development). The concluding chapter of the fourth part looks at what the future holds for Java.

Chapter 11 ("Test-Driven Development") introduces TDD, JUnit, Mockito, and ScalaTest. This chapter also looks at different ways to implement "test doubles" (dummy, stub, fake, mock). Chapter 12 ("Build and Continuous Integration") introduces tools Maven 3, Jenkins, FindBugs, Checkstyle, and Leiningen (for Clojure projects).

Chapter 13 ("Rapid web development") covers issues with developing web applications using Java. It looks at several different popular Java web frameworks before focusing specifically on Grails (Groovy) and Compojure (Clojure).

Chapter 14 ("Staying Well-Grounded") begins with the sentence, "To stay ahead of the curve, the well-grounded Java developer should always be aware of what’s coming around the corner." This chapter then looks at the authors' perspective on the future of Java. The authors cover Java 8 with specific focus on the two most significant features of that version: lambda expressions and Jigsaw modularity. The chapter also looks at JVM changes making polygot programming easier and more productive and at improved concurrency support. It ends by looking at other JVM trends.

Appendices : Background / Supporting Information

Besides the four parts with 14 chapters, The Well-Grounded Java Developer also includes five appendices: Appendix A ("Java7developer - source code installation"), Appendix B ("Glob pattern syntax and examples"), Appendix C ("Installing alternative JVM languages"), Appendix D ("Downloading and installing Jenkins"), and Appendix E ("Java7developer - the Maven POM"). These appendices provide example code related to the book as well as other useful reference information related to topics covered in the book.

The Book's Audience

The Well-Grounded Java Developer hits its goal of being aimed at and primarily beneficial for the Java developer who wants to be a "well-grounded Java developer." Newer Java developers can learn much about basic tools, techniques, and approaches in Java. Moderately experienced Java developers are likely to pick up new tools and techniques or to gain a better and deeper understanding of principles about the Java language and about the JVM.

Most experienced Java developers will likely find much to learn from this book, especially if they are too busy developing applications to spend the time trying out three alternative JVM languages along with the new features of Java in Java 7 and Java 8. I know several Java developers who I consider very experienced and even they would benefit from some of the low-level details this book provides. For example, the sections on javap and jmap are as good as introductions and concise reference as I've seen for those respective Oracle JVM tools.

Although I think nearly all Java developers can learn new things, new approaches, and new techniques from The Well-Grounded Java Developer, I think the book is particularly well-suited for the Java developer who feels comfortable with Java, but has not had a lot of time in recent years to come up to speed on the popular alternative JVM languages or the features of Java 7 and 8 (closures and modularity). This book can provide a quick "tune-up" to bring these experienced Java developers up to speed on the latest happenings.

Disclaimer

It is trendy currently to talk about how "transparent" one is. In an effort to fit in with this trend, I must acknowledge here factors that might be misconstrued as affecting my judgment. First, the authors have kindly included a reference to my blog post on Groovy JSON support in The Well-Grounded Java Developer. This is a book that I'm very happy to have my name and my blog associated with and that may prove my opinion of this book more than anything else.

A second potential conflict of interest that one might misconstrue to affect my judgment is author Martijn Verburg's (@karianna) tweet-out of my Twitter handle (@DustinMarx). That single tweet increased the number of people "following" me on Twitter by several times my previous number. However, I had planned to write this review and had the general gist of it in mind well before this Tweet.

Manning Early Access Program (MEAP)

I enjoyed having access to portions of The Well-Grounded Java Developer earlier than its formal publication via the Manning Early Access Program. This is an especially valuable program when the forthcoming book is on subjects that are very new (such as Java 7).

The Downsides

The Well-Grounded Java Developer's primary downsides are related to the fact that it cannot be everything to everyone (nothing can!). The book is great at helping Java developers kick-start their efforts at becoming well-grounded. However, as the authors acknowledge multiple times in the book, many of the subjects will require additional reading of other sources for more details on subjects introduced in this book. Also, the book cannot possibly cover every "new" thing coming to the world of Java. For example, JavaFX is not mentioned in the book, though the current Java.net poll may end up indicating that JavaFX may not have yet earned enough community-wide respect and acceptance to warrant such a mention.

Conclusion

I was excited about the prospect of The Well-Grounded Java Developer when I initially read about it and it has delivered to a level matching even those high expectations. This is that rare book I'm always on the lookout for that stretches me as a general Java developer. Many highly-focused and specific Java-related books do this for me in one area of Java, but this book helped me to learn and realize things in several different aspects of Java and the JVM.

I have used Java for many years and was a fairly early adopter of Java 7. I have also been a huge fan of Groovy for a while now and I read and write blogs frequently, but I still found numerous details and insights in this book that I had not thought about previously. I work with many great Java developers who spend far less time reading blogs, working with alternative JVM languages, or trying out new features of Java and I'd expect them to gain even more useful insights from reading The Well-Grounded Java Developer. As Dr. Heinz Kabutz wrote in the book's forward, "Studying this book will help you become a well-grounded Java developer. Not only that, it will give you tips on how to stay well-grounded." This book comes from a great idea and is an example of where a delivered product meets the lofty expectations of the original idea.

Thứ Hai, 2 tháng 4, 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.