Tuesday, September 30, 2014

Coverity Code Spotter Beta

Earlier this summer, it was announced on the Coverity Blog and via Andy Chou's Tweet that Coverity Code Spotter Beta is available. That 8 July 2014 blog post describes Coverity Code Spotter as "a free and simple to use cloud-based service built upon Coverity source code analysis technology for finding often hard-to-detect bug-causing issues in Java source code." The blog post also states that "for the duration of the beta period, participants are welcome to upload as much code as they would like and submit builds for analysis as often as they would like.

Yesterday's (29 September 2014) press release (issued in conjunction with JavaOne 2014), "Coverity Launches Code Spotter™ in Free Beta Version to Speed Defect Detection in Java Code," restates some of these observations regarding Coverity Code Spotter. It states, "Built on Coverity’s static code analysis technology, Code Spotter is available for free to the software development community during the beta period." The press release, like the July blog post, describes the types of issues in Java code that Code Spotter detects: "the most common and critical issues in Java code bases, including resource leaks, race conditions, concurrency issues, control flow issues, null pointer dereferences, issues detected by the open source FindBugs tool, copy and paste errors, and many other software defects resulting in incorrect or unpredictable program behavior."

Dennis Chu, Senior Product Manager for Coverity, provided answers to some questions I had. Those questions and answers are shown next.

Q: Is this free for open source and proprietary code bases?
A: Yes, both open source and proprietary Java codes bases can utilize Code Spotter without any limitations during the beta period.

Q: Is the uploaded code made available in any way to others?
A: The uploaded code is kept completely private.

Q: Are the analysis results of the uploaded code available for others with traceability to the code that was analyzed?
A: It is currently possible for a user to download analysis results (which include issues detected as well as code snippets that help understand these issues) and share them with anyone they wish. We are working on a set of team-oriented features that would allow users publish their results to other users within the Code Spotter application.

Q: How long does the uploaded code remain on Coverity's cloud? Can it be completely removed if desired?
A: The code can be completely removed with a click of a button. By default, the code and the results are removed within 30 days of analysis completion. Further, the code is not actually stored on Coverity servers. Instead, the code (and the analysis results) are stored in Amazon's S3 under tight access control.

There is more description on Code Spotter Beta in Chu's blog post Code Spotter Beta: Now Available For Everyone!

Monday, September 22, 2014

ChoiceFormat: Numeric Range Formatting

The Javadoc for the ChoiceFormat class states that ChoiceFormat "allows you to attach a format to a range of numbers" and is "generally used in a MessageFormat for handling plurals." This post describes java.text.ChoiceFormat and provides some examples of applying it in Java code.

One of the most noticeable differences between ChoiceFormat and other "format" classes in the java.text package is that ChoiceFormat does not provide static methods for accessing instances of ChoiceFormat. Instead, ChoiceFormat provides two constructors that are used for instantiating ChoiceFormat objects. The Javadoc for ChoiceFormat highlights and explains this:

ChoiceFormat differs from the other Format classes in that you create a ChoiceFormat object with a constructor (not with a getInstance style factory method). The factory methods aren't necessary because ChoiceFormat doesn't require any complex setup for a given locale. In fact, ChoiceFormat doesn't implement any locale specific behavior.
Constructing ChoiceFormat with Two Arrays

The first of two constructors provided by ChoiceFormat accepts two arrays as its arguments. The first array is an array of primitive doubles that represent the smallest value (starting value) of each interval. The second array is an array of Strings that represent the names associated with each interval. The two arrays must have the same number of elements because there is an assumed one-to-one mapping between the numeric (double) intervals and the Strings describing those intervals. If the two arrays do not have the same number of elements, the following exception is encountered.

Exception in thread "main" java.lang.IllegalArgumentException: Array and limit arrays must be of the same length.

The Javadoc for the ChoiceFormat(double[], String[]) constructor states that the first array parameter is named "limits", is of type double[], and is described as "limits in ascending order." The second array parameter is named "formats", is of type String[], and is described as "corresponding format strings." According to the Javadoc, this constructor "constructs with the limits and the corresponding formats."

Use of the ChoiceFormat constructor accepting two array arguments is demonstrated in the next code listing (the writeGradeInformation(ChoiceFormat) method and fredsTestScores variable will be shown later).

/**
 * Demonstrate ChoiceFormat instantiated with ChoiceFormat
 * constructor that accepts an array of double and an array
 * of String.
 */
public void demonstrateChoiceFormatWithDoublesAndStringsArrays()
{
   final double[] minimumPercentages = {0, 60, 70, 80, 90};
   final String[] letterGrades = {"F", "D", "C", "B", "A"};
   final ChoiceFormat gradesFormat = new ChoiceFormat(minimumPercentages, letterGrades);
   writeGradeInformation(fredsTestScores, gradesFormat);
}

The example above satisfies the expectations of the illustrated ChoiceFormat constructor. The two arrays have the same number of elements, the first (double[]) array has its elements in ascending order, and the second (String[]) array has its "formats" in the same order as the corresponding interval-starting limits in the first array.

The writeGradeInformation(ChoiceFormat) method referenced in the code snippet above demonstrates use of a ChoiceFormat instance based on the two arrays to "format" provided numerical values as Strings. The method's implementation is shown next.

/**
 * Write grade information to standard output
 * using the provided ChoiceFormat instance.
 *
 * @param testScores Test Scores to be displayed with formatting.
 * @param gradesFormat ChoiceFormat instance to be used to format output.
 */
public void writeGradeInformation(
   final Collection<Double> testScores,
   final ChoiceFormat gradesFormat)
{
   double sum = 0;
   for (final Double testScore : testScores)
   {
      sum += testScore;
      out.println(testScore + " is a '" + gradesFormat.format(testScore) + "'.");
   }
   double average = sum / testScores.size();
   out.println(
        "The average score (" + average + ") is a '"
      + gradesFormat.format(average) + "'.");
}

The code above uses the ChoiceFormat instance provided to "format" test scores. Instead of printing a numeric value, the "format" prints the String associated with the interval that numeric value falls within. The next code listing shows the definition of fredsTestScores used in these examples.

private static List<Double> fredsTestScores;
static
{
   final ArrayList<Double> scores = new ArrayList<>();
   scores.add(75.6);
   scores.add(88.8);
   scores.add(97.3);
   scores.add(43.3);
   fredsTestScores = Collections.unmodifiableList(scores);
}

Running these test scores through the ChoiceFormat instance instantiated with two arrays generates the following output:

75.6 is a 'C'.
88.8 is a 'B'.
97.3 is a 'A'.
43.3 is a 'F'.
The average score (76.25) is a 'C'.
Constructing ChoiceFormat with a Pattern String

The ChoiceFormat(String) constructor that accepts a String-based pattern may be more appealing to developers who are comfortable using String-based pattern with similar formatting classes such as DateFormat and DecimalFormat. The next code listing demonstrates use of this constructor. The pattern provided to the constructor leads to an instance of ChoiceFormat that should format the same way as the ChoiceFormat instance created in the earlier example with the constructor that takes two arrays.

/**
 * Demonstrate ChoiceFormat instantiated with ChoiceFormat
 * constructor that accepts a String pattern.
 */
public void demonstrateChoiceFormatWithStringPattern()
{
   final String limitFormatPattern = "0#F | 60#D | 70#C | 80#B | 90#A";
   final ChoiceFormat gradesFormat = new ChoiceFormat(limitFormatPattern);
   writeGradeInformation(fredsTestScores, gradesFormat);
}

The writeGradeInformation method called here is the same as the one called earlier and the output is also the same (not shown here because it is the same).

ChoiceFormat Behavior on the Extremes and Boundaries

The examples so far have worked well with test scores in the expected ranges. Another set of test scores will now be used to demonstrate some other features of ChoiceFormat. This new set of test scores is set up in the next code listing and includes an "impossible" negative score and another "likely impossible" score above 100.

private static List<Double> boundaryTestScores;
static
{
   final ArrayList<Double> boundaryScores = new ArrayList<Double>();
   boundaryScores.add(-25.0);
   boundaryScores.add(0.0);
   boundaryScores.add(20.0);
   boundaryScores.add(60.0);
   boundaryScores.add(70.0);
   boundaryScores.add(80.0);
   boundaryScores.add(90.0);
   boundaryScores.add(100.0);
   boundaryScores.add(115.0);
   boundaryTestScores = boundaryScores;
}

When the set of test scores above is run through either of the ChoiceFormat instances created earlier, the output is as shown next.

-25.0 is a 'F '.
0.0 is a 'F '.
20.0 is a 'F '.
60.0 is a 'D '.
70.0 is a 'C '.
80.0 is a 'B '.
90.0 is a 'A'.
100.0 is a 'A'.
115.0 is a 'A'.
The average score (56.666666666666664) is a 'F '.

The output just shown demonstrates that the "limits" set in the ChoiceFormat constructors are "inclusive," meaning that those limits apply to the specified limit and above (until the next limit). In other words, the range of number is defined as greater than or equal to the specified limit. The Javadoc documentation for ChoiceFormat describes this with a mathematical description:

X matches j if and only if limit[j] ≤ X < limit[j+1]

The output from the boundaries test scores example also demonstrates another characteristic of ChoiceFormat described in its Javadoc documentation: "If there is no match, then either the first or last index is used, depending on whether the number (X) is too low or too high." Because there is no match for -25.0 in the provided ChoiceFormat instances, the lowest ('F' for limit of 0) range is applied to that number lower than the lowest range. In these test score examples, there is no higher limit specified than the "90" for an "A", so all scores higher than 90 (including those above 100) are for "A". Let's suppose that we wanted to enforce the ranges of scores to be between 0 and 100 or else have the formatted result indicate "Invalid" for scores less than 0 or greater than 100. This can be done as shown in the next code listing.

/**
 * Demonstrating enforcing of lower and upper boundaries
 * with ChoiceFormat instances.
 */
public void demonstrateChoiceFormatBoundariesEnforced()
{
   // Demonstrating boundary enforcement with ChoiceFormat(double[], String[])
   final double[] minimumPercentages = {Double.NEGATIVE_INFINITY, 0, 60, 70, 80, 90, 100.000001};
   final String[] letterGrades = {"Invalid - Too Low", "F", "D", "C", "B", "A", "Invalid - Too High"};
   final ChoiceFormat gradesFormat = new ChoiceFormat(minimumPercentages, letterGrades);
   writeGradeInformation(boundaryTestScores, gradesFormat);

   // Demonstrating boundary enforcement with ChoiceFormat(String)
   final String limitFormatPattern = "-\u221E#Invalid - Too Low | 0#F | 60#D | 70#C | 80#B | 90#A | 100.0<Invalid - Too High";
   final ChoiceFormat gradesFormat2 = new ChoiceFormat(limitFormatPattern);
   writeGradeInformation(boundaryTestScores, gradesFormat2);
}

When the above method is executed, its output shows that both approaches enforce boundary conditions better.

-25.0 is a 'Invalid - Too Low'.
0.0 is a 'F'.
20.0 is a 'F'.
60.0 is a 'D'.
70.0 is a 'C'.
80.0 is a 'B'.
90.0 is a 'A'.
100.0 is a 'A'.
115.0 is a 'Invalid - Too High'.
The average score (56.666666666666664) is a 'F'.
-25.0 is a 'Invalid - Too Low '.
0.0 is a 'F '.
20.0 is a 'F '.
60.0 is a 'D '.
70.0 is a 'C '.
80.0 is a 'B '.
90.0 is a 'A '.
100.0 is a 'A '.
115.0 is a 'Invalid - Too High'.
The average score (56.666666666666664) is a 'F '.

The last code listing demonstrates using Double.NEGATIVE_INFINITY and \u221E (Unicode INFINITY character) to establish a lowest possible limit boundary in each of the examples. For scores above 100.0 to be formatted as invalid, the arrays-based ChoiceFormat uses a number slightly bigger than 100 as the lower limit of that invalid range. The String/pattern-based ChoiceFormat instance provides greater flexibility and exactness in specifying the lower limit of the "Invalid - Too High" range as any number greater than 100.0 using the less-than symbol (<).

Handling None, Singular, and Plural with ChoiceFormat

I opened this post by quoting the Javadoc stating that ChoiceFormat is "generally used in a MessageFormat for handling plurals," but have not yet demonstrated this common use in this post. I will demonstrate a portion of this (plurals without MessageFormat) very briefly here for completeness, but a much more complete explanation (plurals with MessageFormat) of this common usage of ChoiceFormat is available in the Java Tutorials' Handling Plurals lesson (part of the Internationalization trail).

The next code listing demonstrates application of ChoiceFormat to handle singular and plural cases.

/**
 * Demonstrate ChoiceFormat used for differentiation of
 * singular from plural and none.
 */
public void demonstratePluralAndSingular()
{
   final double[] cactiLowerLimits = {0, 1, 2, 3, 4, 10};
   final String[] cactiRangeDescriptions =
      {"no cacti", "a cactus", "a couple cacti", "a few cacti", "many cacti", "a plethora of cacti"};
   final ChoiceFormat cactiFormat = new ChoiceFormat(cactiLowerLimits, cactiRangeDescriptions);
   for (int cactiCount = 0; cactiCount < 11; cactiCount++)
   {
      out.println(cactiCount + ": I own " + cactiFormat.format(cactiCount) + ".");
   }
}

Running the example in the last code listing leads to output that is shown next.

0: I own no cacti.
1: I own a cactus.
2: I own a couple cacti.
3: I own a few cacti.
4: I own many cacti.
5: I own many cacti.
6: I own many cacti.
7: I own many cacti.
8: I own many cacti.
9: I own many cacti.
10: I own a plethora of cacti.
One Final Symbol Supported by ChoiceFormat's Pattern

One other symbol that ChoiceFormat pattern parsing recognizes for formatting strings from a generated numeric value is the \u2264 (). This is demonstrated in the next code listing and the output for that code that follows the code listing. Note that in this example the \u2264 works effectively the same as using the simpler # sign shown earlier.

/**
 * Demonstrate using \u2264 in String pattern for ChoiceFormat
 * to represent >= sign. Treated differently than less-than
 * sign but similarly to #.
 */
public void demonstrateLessThanOrEquals()
{
   final String limitFormatPattern = "0\u2264F | 60\u2264D | 70\u2264C | 80\u2264B | 90\u2264A";
   final ChoiceFormat gradesFormat = new ChoiceFormat(limitFormatPattern);
   writeGradeInformation(fredsTestScores, gradesFormat);
}
75.6 is a 'C '.
88.8 is a 'B '.
97.3 is a 'A'.
43.3 is a 'F '.
The average score (76.25) is a 'C '.
Observations in Review

In this section, I summarize some of the observations regarding ChoiceFormat made during the course of this post and its examples.

  • When using the ChoiceFormat(double[], String[]) constructor, the two passed-in arrays must be of equal size or else an IllegalArgumentException ("Array and limit arrays must be of the same length.") will be thrown.
  • The "limits" double[] array provided to the ChoiceFormat(double[], String[]) constructor constructor should have the limits listed from left-to-right in ascending numerical order. When this is not the case, no exception is thrown, but the logic is almost certainly not going to be correct as Strings being formatted against the instance of ChoiceFormat will "match" incorrectly. This same expectation applies to the constructor accepting a pattern.
  • ChoiceFormat allows Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY to be used for specifying lower range limits via its two-arrays constructor.
  • ChoiceFormat allows \u221E and -\u221E to be used for specifying lower range limits via its single String (pattern) constructor.
  • The ChoiceFormat constructor accepting a String pattern is a bit more flexible than the two-arrays constructor and allows one to specify lower limit boundaries as everything over a certain amount without including that certain amount exactly.
  • Symbols and characters with special meaning in the String patterns provided to the single String ChoiceFormat constructor include #, <, \u2264 (), \u221E (), and |.
Conclusion

ChoiceFormat allows formatting of numeric ranges to be customized so that specific ranges can have different and specific representations. This post has covered several different aspects of numeric range formatting with ChoiceFormat, but parsing numeric ranges from Strings using ChoiceFormat was not covered in this post.

Further Reading

Monday, September 15, 2014

Improving LibreOffice with Coverity Scan

Coverity, Inc. issued a press release this morning announcing that "the LibreOffice team" has "analyzed more than 9 million lines of code to find and fix more than 6,000 defects." In the press release, Zack Samocha, senior director of products for Coverity, states, "LibreOffice’s remarkable results after just two years [since October 2012] of using the Coverity Scan service reiterates the mission criticality of software testing for the open source community to find and fix software defects early."

This press release cites the Coverity Scan 2013 Open Source Report in explaining the degree of success the LibreOffice team has achieved. Specifically, according to the press release, the LibreOffice team has "reduced the project’s defect density from .8 to .08."

I was curious about some of the specific details associated with LibreOffice's use of Coverity Scan to reduce defects and improve quality and so took advantage of an offer to ask Zack Samocha some questions. The remainder of this post indicates my questions, Zack's answers, and some related references.

Q: What programming languages are used for LibreOffice (all/mostly C++ or some Java or other languages)?
A: The language used for LibreOffice is mostly C++.

Q: What is an example of one of the most common types of defects discovered and fixed in LibreOffice?
A: The top issues were:

  • Error handling issues = 2271
  • Null pointer dereferences = 1796
  • Uninitialized members = 1145

Q: Is this typical of other open source projects analyzed with Coverity Scan?
A: This is comparable for OSS projects [with more than] 1 million lines of code (LOC)

Q: What is an example of one of the most serious types of defects (high-impact) discovered and fixed? Is this typical of other open source projects analyzed with Coverity Scan?
A: The most serious are memory related. For example, memory-illegal accesses (there were 23) and memory–corruptions (there were 17). This amount is common for such large code base.

Q: Are there any additional metrics regarding the fixes to LibreOffice using Coverity Scan such as number of developers or number of person hours spent on the effort? Is there any estimate of how much of this effort was identifying the issues (running the scan) versus fixing them and testing the fixes?
A: In the past year, LibreOffice fixed more than 8,500 defects, assuming at least one hour per defects, which is conservative. That's about 365 days of work for a single developer.

Q: How does Coverity Scan differ from FindBugs, PMD, other static analysis tools, and IDEs' built-in static analysis support? What advantages does Coverity Scan offer instead of or in addition to those tools?
A: At Coverity, we believe in open source collaboration. Coverity complements Findbugs, PMD and others. In fact, in Coverity Scan and our enterprise products, we provide FindBugs defects in the same workflow as defects found by Coverity development testing solutions. Coverity and FindBugs are looking for different things. Coverity is designed to find critical, crash-causing defects where FindBugs is best suited for find coding-style and best practice-type issues. To illustrate the point, we conducted an experiment with the Jenkins open source build server under a controlled environment. We found 296 critical defects while FingBugs found 1010 coding style issues. There were only 30 defects that were found by both solutions. Coverity analysis tends to be more inter procedural, in addition Coverity covers OWASP10 for Security issues.

Related References

Thursday, September 11, 2014

Date/Time Formatting/Parsing, Java 8 Style

Since nearly the beginning of Java, Java developers have worked with dates and times via the java.util.Date class (since JDK 1.0) and then the java.util.Calendar class (since JDK 1.1). During this time, hundreds of thousands (or maybe millions) of Java developers have formatted and parsed Java dates and times using java.text.DateFormat and java.text.SimpleDateFormat. Given how frequently this has been done over the years, it's no surprise that there are numerous online examples of and tutorials on parsing and formatting dates and times with these classes. The classic Java Tutorials cover these java.util and java.text classes in the Formatting lesson (Dates and Times). The new Date Time trail in the Java Tutorials covers Java 8's new classes for dates and times and their formatting and parsing. This post provides examples of these in action.

Before demonstrating Java 8 style date/time parsing/formatting with examples, it is illustrative to compare the Javadoc descriptions for DateFormat/SimpleDateFormat and DateTimeFormatter. The table that follows contains differentiating information that can be gleaned directly or indirectly from a comparison of the Javadoc for each formatting class. Perhaps the most important observations to make from this table are that the new DateTimeFormatter is threadsafe and immutable and the general overview of the APIs that DateTimeFormatter provides for parsing and formatting dates and times.

Characteristic DateFormat/SimpleDateFormat DateTimeFormatter
Purpose "formats and parses dates or time in a language-independent manner" "Formatter for printing and parsing date-time objects."
Primarily Used With java.util.Date
java.util.Calendar
java.time.LocalDate
java.time.LocalTime
java.time.LocalDateTime
java.time.OffsetTime
java.time.OffsetDateTime
java.time.ZonedDateTime
java.time.Instant
Thread Safety "Date formats are not synchronized." "This class is immutable and thread-safe."
Direct Formatting format(Date) format(TemporalAccessor)
Direct Parsing parse(String) parse(CharSequence, TemporalQuery)
Indirect Formatting None [unless you use Groovy's Date.format(String) extension)] LocalDate.format(DateTimeFormatter)
LocalTime.format(DateTimeFormatter)
LocalDateTime.format(DateTimeFormatter)
OffsetTime.format(DateTimeFormatter)
OffsetDateTime.format(DateTimeFormatter)
ZonedDateTime.format(DateTimeFormatter)
Indirect Parsing None [unless you use deprecated Date.parse(String) or Groovy's Date.parse(String, String) extension] LocalDate.parse(CharSequence, DateTimeFormatter)
LocalTime.parse(CharSequence, DateTimeFormatter)
LocalDateTime.parse(CharSequence, DateTimeFormatter)
OffsetTime.parse(CharSequence, DateTimeFormatter)
OffsetDateTime.parse(CharSequence, DateTimeFormatter)
ZonedDateTime.parse(CharSequence, DateTimeFormatter)
Internationalization java.util.Locale java.util.Locale
Time Zone java.util.TimeZone java.time.ZoneId
java.time.ZoneOffset
Predefined Formatters None, but does offer static convenience methods for common instances:
getDateInstance()
getDateInstance(int)
getDateInstance(int, Locale)
getDateTimeInstance()
getDateTimeInstance(int, int)
getDateTimeInstance(int, int, Locale)
getInstance()
getTimeInstance()
getTimeInstance(int)
getTimeInstance(int, Locale)
ISO_LOCAL_DATE
ISO_LOCAL_TIME
ISO_LOCAL_DATE_TIME
ISO_OFFSET_DATE
ISO_OFFSET_TIME
ISO_OFFSET_DATE_TIME
ISO_ZONED_DATE_TIME
BASIC_ISO_DATE
ISO_DATE
ISO_DATE_TIME
ISO_ORDINAL_DATE
ISO_INSTANTISO_WEEK_DATE
RFC_1123_DATE_TIME

The remainder of this post uses examples to demonstrate formatting and parsing dates in Java 8 with the java.time constructs. The examples will use the following string patterns and instances.

/** Pattern to use for String representation of Dates/Times. */
private final String dateTimeFormatPattern = "yyyy/MM/dd HH:mm:ss z";

/**
 * java.util.Date instance representing now that can
 * be formatted using SimpleDateFormat based on my
 * dateTimeFormatPattern field.
 */
private final Date now = new Date();

/**
 * java.time.ZonedDateTime instance representing now that can
 * be formatted using DateTimeFormatter based on my
 * dateTimeFormatPattern field.
 *
 * Note that ZonedDateTime needed to be used in this example
 * instead of java.time.LocalDateTime or java.time.OffsetDateTime
 * because there is zone information in the format provided by
 * my dateTimeFormatPattern field and attempting to have
 * DateTimeFormatter.format(TemporalAccessor) instantiated
 * with a format pattern that includes time zone details
 * will lead to DateTimeException for instances of
 * TemporalAccessor that do not have time zone information
 * (such as LocalDateTime and OffsetDateTime).
 */
private final ZonedDateTime now8 = ZonedDateTime.now();


/**
 * String that can be used by both SimpleDateFormat and
 * DateTimeFormatter to parse respective date/time instances
 * from this String.
 */
private final String dateTimeString = "2014/09/03 13:59:50 MDT";

Before Java 8, the standard Java approach for dates and times was via the Date and Calendar classes and the standard approach to parsing and formatting dates was via DateFormat and SimpleDateFormat. The next code listing demonstrates these classical approaches.

Formatting and Parsing Java Dates with SimpleDateFormat
/**
 * Demonstrate presenting java.util.Date as String matching
 * provided pattern via use of SimpleDateFormat.
 */
public void demonstrateSimpleDateFormatFormatting()
{
   final DateFormat format = new SimpleDateFormat(dateTimeFormatPattern);
   final String nowString = format.format(now);
   out.println(
        "Date '" + now + "' formatted with SimpleDateFormat and '"
      + dateTimeFormatPattern + "': " + nowString);
}

/**
 * Demonstrate parsing a java.util.Date from a String
 * via SimpleDateFormat.
 */
public void demonstrateSimpleDateFormatParsing()
{
   final DateFormat format = new SimpleDateFormat(dateTimeFormatPattern);
   try
   {
      final Date parsedDate = format.parse(dateTimeString);
      out.println("'" + dateTimeString + "' is parsed with SimpleDateFormat as " + parsedDate);
   }
   // DateFormat.parse(String) throws a checked exception
   catch (ParseException parseException)
   {
      out.println(
           "ERROR: Unable to parse date/time String '"
         + dateTimeString + "' with pattern '"
         + dateTimeFormatPattern + "'.");
   }
}

With Java 8, the preferred date/time classes are no longer in the java.util package and the preferred date/time handling classes are now in the java.time package. Similarly, the preferred date/time formatting/parsing classes are no longer in the java.text package, but instead come from the java.time.format package.

The java.time package offers numerous classes for modeling dates and/or times. These include classes that model dates only (no time information), classes that model times only (no date information), classes that model date and time information, classes that use timezone information, and classes that do not incorporate time zone information. The approach for formatting and parsing these is generally similar, though the characteristics of the class (whether it supports date or time or timezone information, for example) affects which patterns that can be applied. In this post, I use the ZonedDateTime class for my examples. The reason for this choice is that it includes date, time, and time zone information and allows me to use a matching pattern that involves all three of those characteristics like a Date or Calendar instance does. This makes it easier to compare the old and new approaches.

The DateTimeFormatter class provides ofPattern methods to provide an instance of DateTimeFormatter based on the provided date/time pattern String. One of the format methods can then be called on that instance of DateTimeFormatter to get the date and/or time information formatted as a String matching the provided pattern. The next code listing illustrates this approach to formatting a String from a ZonedDateTime based on the provided pattern.

Formatting ZonedDateTime as String
/**
 * Demonstrate presenting ZonedDateTime as a String matching
 * provided pattern via DateTimeFormatter and its
 * ofPattern(String) method.
 */
public void demonstrateDateTimeFormatFormatting()
{
   final DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(dateTimeFormatPattern);
   final String nowString = formatter.format(now8);
   out.println(
        now8 + " formatted with DateTimeFormatter and '"
      + dateTimeFormatPattern + "': " + nowString);
}

Parsing a date/time class from a String based on a pattern is easily accomplished. There are a couple ways this can be accomplished. One approach is to pass the instance of DateTimeFormatter to the static ZonedDateTime.parse(CharSequence, DateTimeFormatter) method, which returns an instance of ZonedDateTime derived from the provided character sequence and based on the provided pattern. This is illustrated in the next code listing.

Parsing ZonedDateTime from String Using Static ZonedDateTime.parse Method
/**
 * Demonstrate parsing ZonedDateTime from provided String
 * via ZonedDateTime's parse(String, DateTimeFormatter) method.
 */
public void demonstrateDateTimeFormatParsingTemporalStaticMethod()
{
   final DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(dateTimeFormatPattern);
   final ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeString, formatter);
   out.println(
        "'" + dateTimeString
      + "' is parsed with DateTimeFormatter and ZonedDateTime.parse as "
      + zonedDateTime);
}

A second approach to parsing ZonedDateTime from a String is via DateTimeFormatter's parse(CharSequence, TemporalQuery<T>) method. This is illustrated in the next code listing which also provides an opportunity to demonstrate use of a Java 8 method reference (see ZonedDateTime::from).

Parsing ZonedDateTime from String Using DateTimeFormatter.parse Method
/**
 * Demonstrate parsing ZonedDateTime from String
 * via DateTimeFormatter.parse(String, TemporaryQuery)
 * with the Temple Query in this case being ZonedDateTime's
 * from(TemporalAccessor) used as a Java 8 method reference.
 */
public void demonstrateDateTimeFormatParsingMethodReference()
{
   final DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(dateTimeFormatPattern);
   final ZonedDateTime zonedDateTime = formatter.parse(dateTimeString, ZonedDateTime::from);
   out.println(
        "'" + dateTimeString
      + "' is parsed with DateTimeFormatter and ZoneDateTime::from as "
      + zonedDateTime);
}

Very few projects have the luxury of being a greenfield project that can start with Java 8. Therefore, it's helpful that there are classes that connect the pre-JDK 8 date/time classes with the new date/time classes introduced in JDK 8. One example of this is the ability of JDK 8's DateTimeFormatter to provide a descending instance of the pre-JDK 8 abstract Format class via the DateTimeFormatter.toFormat() method. This is demonstrated in the next code listing.

Accessing Pre-JDK 8 Format from JDK 8's DateTimeFormatter
/**
 * Demonstrate formatting ZonedDateTime via DateTimeFormatter,
 * but using implementation of Format.
 */
public void demonstrateDateTimeFormatAndFormatFormatting()
{
   final DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(dateTimeFormatPattern);
   final Format format = formatter.toFormat();
   final String nowString = format.format(now8);
   out.println(
        "ZonedDateTime " + now + " formatted with DateTimeFormatter/Format (and "
      + format.getClass().getCanonicalName() + ") and '"
      + dateTimeFormatPattern + "': " + nowString);
}

The Instant class is especially important when working with both pre-JDK 8 Date and Calendar classes in conjunction with the new date and time classes introduced with JDK 8. The reason Instant is so important is that java.util.Date has methods from(Instant) and toInstant() for getting a Date from an Instant and getting an Instant from a Date respectively. Because Instant is so important in migrating pre-Java 8 date/time handling to Java 8 baselines, the next code listing demonstrates formatting and parsing instances of Instant.

Formatting and Parsing Instances of Instant
/**
 * Demonstrate formatting and parsing an instance of Instant.
 */
public void demonstrateDateTimeFormatFormattingAndParsingInstant()
{
   // Instant instances don't have timezone information
   final Instant instant = now.toInstant();
   final DateTimeFormatter formatter =
      DateTimeFormatter.ofPattern(
         dateTimeFormatPattern).withZone(ZoneId.systemDefault());
   final String formattedInstance = formatter.format(instant);
   out.println(
        "Instant " + instant + " formatted with DateTimeFormatter and '"
      + dateTimeFormatPattern + "' to '" + formattedInstance + "'");
   final Instant instant2 =
      formatter.parse(formattedInstance, ZonedDateTime::from).toInstant();
      out.println(formattedInstance + " parsed back to " + instant2);
}

All of the above examples come from the sample class shown in the next code listing for completeness.

DateFormatDemo.java
package dustin.examples.numberformatdemo;

import static java.lang.System.out;

import java.text.DateFormat;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * Demonstrates formatting dates as strings and parsing strings
 * into dates and times using pre-Java 8 (java.text.SimpleDateFormat)
 * and Java 8 (java.time.format.DateTimeFormatter) mechanisms.
 */
public class DateFormatDemo
{
   /** Pattern to use for String representation of Dates/Times. */
   private final String dateTimeFormatPattern = "yyyy/MM/dd HH:mm:ss z";

   /**
    * java.util.Date instance representing now that can
    * be formatted using SimpleDateFormat based on my
    * dateTimeFormatPattern field.
    */
   private final Date now = new Date();

   /**
    * java.time.ZonedDateTime instance representing now that can
    * be formatted using DateTimeFormatter based on my
    * dateTimeFormatPattern field.
    *
    * Note that ZonedDateTime needed to be used in this example
    * instead of java.time.LocalDateTime or java.time.OffsetDateTime
    * because there is zone information in the format provided by
    * my dateTimeFormatPattern field and attempting to have
    * DateTimeFormatter.format(TemporalAccessor) instantiated
    * with a format pattern that includes time zone details
    * will lead to DateTimeException for instances of
    * TemporalAccessor that do not have time zone information
    * (such as LocalDateTime and OffsetDateTime).
    */
   private final ZonedDateTime now8 = ZonedDateTime.now();


   /**
    * String that can be used by both SimpleDateFormat and
    * DateTimeFormatter to parse respective date/time instances
    * from this String.
    */
   private final String dateTimeString = "2014/09/03 13:59:50 MDT";

   /**
    * Demonstrate presenting java.util.Date as String matching
    * provided pattern via use of SimpleDateFormat.
    */
   public void demonstrateSimpleDateFormatFormatting()
   {
      final DateFormat format = new SimpleDateFormat(dateTimeFormatPattern);
      final String nowString = format.format(now);
      out.println(
           "Date '" + now + "' formatted with SimpleDateFormat and '"
         + dateTimeFormatPattern + "': " + nowString);
   }

   /**
    * Demonstrate parsing a java.util.Date from a String
    * via SimpleDateFormat.
    */
   public void demonstrateSimpleDateFormatParsing()
   {
      final DateFormat format = new SimpleDateFormat(dateTimeFormatPattern);
      try
      {
         final Date parsedDate = format.parse(dateTimeString);
         out.println("'" + dateTimeString + "' is parsed with SimpleDateFormat as " + parsedDate);
      }
      // DateFormat.parse(String) throws a checked exception
      catch (ParseException parseException)
      {
         out.println(
              "ERROR: Unable to parse date/time String '"
            + dateTimeString + "' with pattern '"
            + dateTimeFormatPattern + "'.");
      }
   }

   /**
    * Demonstrate presenting ZonedDateTime as a String matching
    * provided pattern via DateTimeFormatter and its
    * ofPattern(String) method.
    */
   public void demonstrateDateTimeFormatFormatting()
   {
      final DateTimeFormatter formatter =
         DateTimeFormatter.ofPattern(dateTimeFormatPattern);
      final String nowString = formatter.format(now8);
      out.println(
           now8 + " formatted with DateTimeFormatter and '"
         + dateTimeFormatPattern + "': " + nowString);
   }

   /**
    * Demonstrate parsing ZonedDateTime from provided String
    * via ZonedDateTime's parse(String, DateTimeFormatter) method.
    */
   public void demonstrateDateTimeFormatParsingTemporalStaticMethod()
   {
      final DateTimeFormatter formatter =
         DateTimeFormatter.ofPattern(dateTimeFormatPattern);
      final ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeString, formatter);
      out.println(
           "'" + dateTimeString
         + "' is parsed with DateTimeFormatter and ZonedDateTime.parse as "
         + zonedDateTime);
   }

   /**
    * Demonstrate parsing ZonedDateTime from String
    * via DateTimeFormatter.parse(String, TemporaryQuery)
    * with the Temple Query in this case being ZonedDateTime's
    * from(TemporalAccessor) used as a Java 8 method reference.
    */
   public void demonstrateDateTimeFormatParsingMethodReference()
   {
      final DateTimeFormatter formatter =
         DateTimeFormatter.ofPattern(dateTimeFormatPattern);
      final ZonedDateTime zonedDateTime = formatter.parse(dateTimeString, ZonedDateTime::from);
      out.println(
           "'" + dateTimeString
         + "' is parsed with DateTimeFormatter and ZoneDateTime::from as "
         + zonedDateTime);
   }

   /**
    * Demonstrate formatting ZonedDateTime via DateTimeFormatter,
    * but using implementation of Format.
    */
   public void demonstrateDateTimeFormatAndFormatFormatting()
   {
      final DateTimeFormatter formatter =
         DateTimeFormatter.ofPattern(dateTimeFormatPattern);
      final Format format = formatter.toFormat();
      final String nowString = format.format(now8);
      out.println(
           "ZonedDateTime " + now + " formatted with DateTimeFormatter/Format (and "
         + format.getClass().getCanonicalName() + ") and '"
         + dateTimeFormatPattern + "': " + nowString);
   }

   /**
    * Demonstrate formatting and parsing an instance of Instant.
    */
   public void demonstrateDateTimeFormatFormattingAndParsingInstant()
   {
      // Instant instances don't have timezone information
      final Instant instant = now.toInstant();
      final DateTimeFormatter formatter =
         DateTimeFormatter.ofPattern(
            dateTimeFormatPattern).withZone(ZoneId.systemDefault());
      final String formattedInstance = formatter.format(instant);
      out.println(
           "Instant " + instant + " formatted with DateTimeFormatter and '"
         + dateTimeFormatPattern + "' to '" + formattedInstance + "'");
      final Instant instant2 =
         formatter.parse(formattedInstance, ZonedDateTime::from).toInstant();
      out.println(formattedInstance + " parsed back to " + instant2);
   }

   /**
    * Demonstrate java.text.SimpleDateFormat and
    * java.time.format.DateTimeFormatter.
    *
    * @param arguments Command-line arguments; none anticipated.
    */
   public static void main(final String[] arguments)
   {
      final DateFormatDemo demo = new DateFormatDemo();
      out.print("\n1: ");
      demo.demonstrateSimpleDateFormatFormatting();
      out.print("\n2: ");
      demo.demonstrateSimpleDateFormatParsing();
      out.print("\n3: ");
      demo.demonstrateDateTimeFormatFormatting();
      out.print("\n4: ");
      demo.demonstrateDateTimeFormatParsingTemporalStaticMethod();
      out.print("\n5: ");
      demo.demonstrateDateTimeFormatParsingMethodReference();
      out.print("\n6: ");
      demo.demonstrateDateTimeFormatAndFormatFormatting();
      out.print("\n7: ");
      demo.demonstrateDateTimeFormatFormattingAndParsingInstant();
   }
}

The output from running the above demonstration is shown in the next screen snapshot.

Conclusion

The JDK 8 date/time classes and related formatting and parsing classes are much more straightforward to use than their pre-JDK 8 counterparts. This post has attempted to demonstrate how to apply these new classes and to take advantage of some of their benefits.

Saturday, August 30, 2014

Big Java News in Late Summer 2014

As is typical when JavaOne is imminent, there has been much big news in the Java community recently. This post briefly references three of these items (Java SE 8 updates, Java SE 9, and Java EE 8) and a "bonus" reference to a post I found to be one of the clearer ones I have seen on classpath/classloader issues.

String Deduplication in Oracle Java 8 JVM

In String Deduplication – A new feature in Java 8 Update 20, Fabian Lange introduces String Deduplication for the G1 Garbage Collector using the JVM option -XX:+UseStringDeduplication that was introduced with JDK 8 Update 20. The tools page for the Java launcher has been updated to mention the JVM options -XX:+UseStringDeduplication, -XX:+PrintStringDeduplicationStatistics, and -XX:StringDeduplicationAgeThreshold. More details on JDK 8 Update 20 are available in the blog post Release: Oracle Java Development Kit 8, Update 20. The Lange post has also sparked discussion on this and related JVM options on the Java subreddit.

Java 9 Features

Java 9 has been the hot topic of discussion in the Java community since the OpenJDK JDK 9 Project was announced. Long-awaited Java modularity (Project Jigsaw, which was booted from JDK 8) is probably the largest new feature anticipated for Java 9. Paul Krill writes in Why developers should get excited about Java 9 that "Jigsaw isn't the only new addition slated for Java 9. Support for the popular JSON (JavaScript Object Notation) data interchange format is key feature as well, along with process API, code cache, and locking improvements. The six JEPs currently proposed on that OpenJDK JDK 9 page are 102 (Process API Updates), 143 (Improve Contended Locking), 197 (Segmented Code Cache), 198 (Light-Weight JSON API), 199 (Smart Java Compilation, Phase 2), and 201 (Modular Source Code).

In the blog post Java 9 is coming with money api, otaviojava introduces JSR 354 ("JSR 354: Money and Currency API"), describes why it is needed, covers how it might be implemented, and concludes, "this API is expected to [be in] Java 9."

Java EE 8

Reza Rahman's post Java EE 8 Takes Off! talks about JSR 366 (Java EE 8 Specification) being kicked off. This post lists some of the anticipated high-level content for Java EE along with links to related JSRs.

Demystifying the Java Classpath

Java classpath issues are definitely one of the more difficult challenges that Java developers can face. The post Jar Hell made Easy - Demystifying the classpath with jHades provides a nice overview of some of the most common issues related to classpath and classloaders with concise and simple explanations of why these occur. I have not used jHades, but the quality of this post has definitely sparked my interest in that tool.

Conclusion

"Java" (SE, EE, JVM, etc.) keeps advancing and bringing us new language features, libraries, and tools. This post has referenced posts that highlight recent developments in JDK 8, JDK 9, and Java EE 8.

Friday, August 22, 2014

Java Numeric Formatting

I can think of numerous times when I have seen others write unnecessary Java code and I have written unnecessary Java code because of lack of awareness of a JDK class that already provides the desired functionality. One example of this is the writing of time-related constants using hard-coded values such as 60, 24, 1440, and 86400 when TimeUnit provides a better, standardized approach. In this post, I look at another example of a class that provides the functionality I have seen developers often implement on their one: NumberFormat.

The NumberFormat class is part of the java.text package, which also includes the frequently used DateFormat and SimpleDateFormat classes. NumberFormat is an abstract class (no public constructor) and instances of its descendants are obtained via overloaded static methods with names such as getInstance(), getCurrencyInstance(), and getPercentInstance().

Currency

The next code listing demonstrates calling NumberFormat.getCurrencyInstance(Locale) to get an instance of NumberFormat that presents numbers in a currency-friendly format.

Demonstrating NumberFormat's Currency Support
/**
 * Demonstrate use of a Currency Instance of NumberFormat.
 */
public void demonstrateCurrency()
{
   writeHeaderToStandardOutput("Currency NumberFormat Examples");
   final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
   out.println("15.5      -> " + currencyFormat.format(15.5));
   out.println("15.54     -> " + currencyFormat.format(15.54));
   out.println("15.345    -> " + currencyFormat.format(15.345));  // rounds to two decimal places
   printCurrencyDetails(currencyFormat.getCurrency());
}

/**
 * Print out details of provided instance of Currency.
 *
 * @param currency Instance of Currency from which details
 *    will be written to standard output.
 */
public void printCurrencyDetails(final Currency currency)
{
   out.println("Concurrency: " + currency);
   out.println("\tISO 4217 Currency Code:           " + currency.getCurrencyCode());
   out.println("\tISO 4217 Numeric Code:            " + currency.getNumericCode());
   out.println("\tCurrency Display Name:            " + currency.getDisplayName(Locale.US));
   out.println("\tCurrency Symbol:                  " + currency.getSymbol(Locale.US));
   out.println("\tCurrency Default Fraction Digits: " + currency.getDefaultFractionDigits());
}

When the above code is executed, the results are as shown next:

==================================================================================
= Currency NumberFormat Examples
==================================================================================
15.5      -> $15.50
15.54     -> $15.54
15.345    -> $15.35
Concurrency: USD
 ISO 4217 Currency Code:           USD
 ISO 4217 Numeric Code:            840
 Currency Display Name:            US Dollar
 Currency Symbol:                  $
 Currency Default Fraction Digits: 2

The above code and associated output demonstrate that the NumberFormat instance used for currency (actually a DecimalFormat), automatically applies the appropriate number of digits and appropriate currency symbol based on the locale.

Percentages

The next code listings and associated output demonstrate use of NumberFormat to present numbers in percentage-friendly format.

Demonstrating NumberFormat's Percent Format
/**
 * Demonstrate use of a Percent Instance of NumberFormat.
 */
public void demonstratePercentage()
{
   writeHeaderToStandardOutput("Percentage NumberFormat Examples");
   final NumberFormat percentageFormat = NumberFormat.getPercentInstance(Locale.US);
   out.println("Instance of: " + percentageFormat.getClass().getCanonicalName());
   out.println("1        -> " + percentageFormat.format(1));
   // will be 0 because truncated to Integer by Integer division
   out.println("75/100   -> " + percentageFormat.format(75/100));
   out.println(".75      -> " + percentageFormat.format(.75));
   out.println("75.0/100 -> " + percentageFormat.format(75.0/100));
   // will be 0 because truncated to Integer by Integer division
   out.println("83/93    -> " + percentageFormat.format((83/93)));
   out.println("93/83    -> " + percentageFormat.format(93/83));
   out.println(".5       -> " + percentageFormat.format(.5));
   out.println(".912     -> " + percentageFormat.format(.912));
   out.println("---- Setting Minimum Fraction Digits to 1:");
   percentageFormat.setMinimumFractionDigits(1);
   out.println("1        -> " + percentageFormat.format(1));
   out.println(".75      -> " + percentageFormat.format(.75));
   out.println("75.0/100 -> " + percentageFormat.format(75.0/100));
   out.println(".912     -> " + percentageFormat.format(.912));
}
==================================================================================
= Percentage NumberFormat Examples
==================================================================================
1        -> 100%
75/100   -> 0%
.75      -> 75%
75.0/100 -> 75%
83/93    -> 0%
93/83    -> 100%
.5       -> 50%
.912     -> 91%
---- Setting Minimum Fraction Digits to 1:
1        -> 100.0%
.75      -> 75.0%
75.0/100 -> 75.0%
.912     -> 91.2%

The code and output of the percent NumberFormat usage demonstrate that by default the instance of NumberFormat (actually a DecimalFormat in this case) returned by NumberFormat.getPercentInstance(Locale) method has no fractional digits, multiplies the provided number by 100 (assumes that it is the decimal equivalent of a percentage when provided), and adds a percentage sign (%).

Integers

The small amount of code shown next and its associated output demonstrate use of NumberFormat to present numbers in integral format.

Demonstrating NumberFormat's Integer Format
/**
 * Demonstrate use of an Integer Instance of NumberFormat.
 */
public void demonstrateInteger()
{
   writeHeaderToStandardOutput("Integer NumberFormat Examples");
   final NumberFormat integerFormat = NumberFormat.getIntegerInstance(Locale.US);
   out.println("7.65   -> " + integerFormat.format(7.65));
   out.println("7.5    -> " + integerFormat.format(7.5));
   out.println("7.49   -> " + integerFormat.format(7.49));
   out.println("-23.23 -> " + integerFormat.format(-23.23));
}
==================================================================================
= Integer NumberFormat Examples
==================================================================================
7.65   -> 8
7.5    -> 8
7.49   -> 7
-23.23 -> -23

As demonstrated in the above code and associated output, the NumberFormat method getIntegerInstance(Locale) returns an instance that presents provided numerals as integers.

Fixed Digits

The next code listing and associated output demonstrate using NumberFormat to print fixed-point representation of floating-point numbers. In other words, this use of NumberFormat allows one to represent a number with an exactly prescribed number of digits to the left of the decimal point ("integer" digits) and to the right of the decimal point ("fraction" digits).

Demonstrating NumberFormat for Fixed-Point Numbers
/**
 * Demonstrate generic NumberFormat instance with rounding mode,
 * maximum fraction digits, and minimum integer digits specified.
 */
public void demonstrateNumberFormat()
{
   writeHeaderToStandardOutput("NumberFormat Fixed-Point Examples");
   final NumberFormat numberFormat = NumberFormat.getNumberInstance();
   numberFormat.setRoundingMode(RoundingMode.HALF_UP);
   numberFormat.setMaximumFractionDigits(2);
   numberFormat.setMinimumIntegerDigits(1);
   out.println("234.234567 --> " + numberFormat.format(234.234567));
   out.println("1          --> " + numberFormat.format(1));
   out.println(".234567    --> " + numberFormat.format(.234567));
   out.println(".349       --> " + numberFormat.format(.349));
   out.println(".3499      --> " + numberFormat.format(.3499));
   out.println("0.9999     --> " + numberFormat.format(0.9999));
}
==================================================================================
= NumberFormat Fixed-Point Examples
==================================================================================
234.234567 --> 234.23
1          --> 1
.234567    --> 0.23
.349       --> 0.34
.3499      --> 0.35
0.9999     --> 1

The above code and associated output demonstrate the fine-grain control of the minimum number of "integer" digits to represent to the left of the decimal place (at least one, so zero shows up when applicable) and the maximum number of "fraction" digits to the right of the decimal point. Although not shown, the maximum number of integer digits and minimum number of fraction digits can also be specified.

Conclusion

I have used this post to look at how NumberFormat can be used to present numbers in different ways (currency, percentage, integer, fixed number of decimal points, etc.) and often means no or reduced code need be written to massage numbers into these formats. When I first began writing this post, I envisioned including examples and discussion on the direct descendants of NumberFormat (DecimalFormat and ChoiceFormat), but have decided this post is already sufficiently lengthy. I may write about these descendants of NumberFormat in future blog posts.

Tuesday, August 19, 2014

jinfo: Command-line Peeking at JVM Runtime Configuration

In several recent blogs (in my reviews of the books Java EE 7 Performance Tuning and Optimization and WildFly Performance Tuning in particular), I have referenced my own past blog posts on certain Oracle JDK command-line tools. I was aghast to discover that I had never exclusively addressed the nifty jinfo tool and this post sets to rectify that troubling situation. I suspect that the reasons I chose not to write about jinfo previously include limitations related to jinfo discussed in my post VisualVM: jinfo and So Much More.

In the Java SE 8 version of jinfo running on my machine, the primary limitation of jinfo on Windows that I discussed in the post Acquiring JVM Runtime Information has been addressed. In particular, I noted in that post that the -flags option was not supported on Windows version of jinfo at that time. As the next screen snapshot proves, that is no longer the case (note the use of jps to acquire the Java process ID to instruct jinfo to query).

As the above screen snapshot demonstrates, the jinfo -flags command and option show the flags the explicitly specified JVM options of the Java process being monitored.

If I want to find out about other JVM flags that are in effect implicitly (automatically), I can run java -XX:+PrintFlagsFinal to see all default JVM options. I can then query for any one of these against a running JVM process to find out what that particular JVM is using (same default or overridden different value). The next screen snapshot demonstrates how a small portion of the output provided from running java -XX:+PrintFlagsFinal.

Let's suppose I notice a flag called PrintHeapAtGC in the above output and want to know if it's set in my particular Java application (-XX:+PrintHeapAtGC means it's set and -XX:-PrintHeapAtGC means it's not set). I can have jinfo tell me what its setting is (note my choice to use jcmd instead of jps in this case to determine the Java process ID):

Because of the subtraction sign (-) instead of an addition sign (+) after the colon and before "PrintHeapAtGC", we know this is turned off for the Java process with the specified ID. It turns out that jinfo does more than let us look; it also let's us touch. The next screen snapshot shows changing this option using jinfo.

As the previous screen snapshot indicates, I can turn off and on the boolean-style JVM options by simply using the same command to view the flag's setting but preceding the flag's name with the addition sign (+) to turn it on or with the substraction sign (-) to turn it off. In the example just shown, I turned off the PrintGCDateStamps, turned it back on again, and monitored its setting between those changes. Not all JVM options are boolean conditions. In those cases, their new values are assigned to them by concatenating the equals sign (=) and new value after the flag name. It's also important to note that the target JVM (the one you're trying to peek at and touch with jinfo will not allow you to change all its JVM option settings). In such cases, you'll likely see a stack trace with message "Command failed in target VM."

In addition to displaying a currently running JVM's options and allowing the changing of some of these, jinfo also allows one to see system properties used by that JVM as name/value pairs. This is demonstrated in the next screen snapshot with a small fraction of the output shown.

Perhaps the easiest way to run jinfo is to simply provide no arguments other than the PID of the Java process in question and have both JVM options (non-default and command-line) and system properties displayed. Running jinfo -help provides brief usage details. Other important details are found in the Oracle documentation on the jinfo tool. These details includes the common (when it comes to these tools) reminder that this tool is "experimental and unsupported" and "might not be available in future releases of the JDK." We are also warned that jinfo on Windows requires availability of dbgeng.dll or installed Debugging Tools For Windows.

Although I have referenced the handy jinfo command line tool previously in posts VisualVM: jinfo and So Much More and Acquiring JVM Runtime Information, it is a handy enough tool to justify a post of its very own. As a command-line tool, it enjoys benefits commonly associated with command-line tools such as being relatively lightweight, working well with scripts, and working in headless environments.