Friday, May 31, 2013

Java Happenings in May 2013

This post very briefly summarizes some recent (within the past few weeks) developments in the world of Java.

Yet Another Java Versioning Scheme

Oracle has changed the Java version numbering schema again, this time in an effort "to avoid confusion caused by renumbering releases" because of the "recent increase of security releases" that have already led to skipped numbers and renumbered releases.

The Closure of java.blogs

Atlassian's java.blogs is currently closed, though it seems like this may not be permanent if there is sufficient interest in it being restored and updated. There is a form at the main site available for folks interested in it being restored to make that known.

Kicking the Tires of JDK 8

In Feedback Wanted, Java SE 8, Tori Wieldt provides links for downloading the latest released versions of Java SE 8 under development. She also provides links to the source code and to a list of Java Enhancement Proposals that have been incorporated into the latest JDK 8 releases. There are also links for reporting bugs found with a new release and for obtaining help if problems are encountered trying to use a new release.

JDK8 Javadoc Updates

Jonathan Gibbons's post javadoc TLC summarizes recent JDK8 tools fixes and the effect on Javadoc. I previously blogged on some changes in JDK8 Javadoc and its presentation of class methods.

Android, IntelliJ, and Gradle

Google I/O 2013 recently concluded and there were some big announcements in the Android space related to products that are well-known in the Java community. In particular, IntelliJ-based Android Studio is now offered (currently "early access preview") alongside more mature Eclipse-based Eclipse ADT plug-in and Gradle is now the main Android build system.

JAXconf

JAX Conference will be next week (June 4-5) in the Santa Clara Convention Center.

Java EE 7 Kick-off

The webcast Introducing Java EE 7 has been announced and will be broadcast live. Geertjan Wielenga has posted that NetBeans support for Java EE 7 will be featured in this webcast.

New JDK 7 and JDK 8 Early Access Releases

In Food For Tests: 7u40 Build b26 & 8 Build b91, Dalibor Topic writes of the new Early Access releases of JDK 7 Update 40 and JDK 8 Build b91. One thing of particular note is that the new JDK 8 build has "Nashorn replacing Rhino."

Wednesday, May 8, 2013

JDK 8's Calendar.Builder

One of the defining characteristics of the brave new world of Java is the increasing prevalence of the builder pattern in the Java space. Groovy, which appears to be the most popular alternative language (to Java) on the JVM, is well-known for its heavy use of the Builder in both the core libraries and in Groovy-supported libraries and frameworks. Josh Bloch brought the pattern to the forefront of Java developer community mindset with coverage of the pattern in Item #2 of the second edition of his highly influential Effective Java. There have been several builders added to the JDK including the addition of Locale.Builder in J2SE 1.7. In this post, I briefly introduce Calendar.Builder coming to JDK 8.

Today, a Java developer typically populates an instance of the Calendar class by either calling one of the "set" methods that accepts a lengthy list of content for the instance or by calling individual "set" methods on the instance one after another. These two typical approaches for populating a Calendar instance are demonstrated in the next two code listings.

Populating Calendar with Single 'set' Method
/**
 * Demonstrate pre-JDK 8 method of instantiating Calendar instance using
 * "set" method for main fields.
 */
public static void demoCalendarWithSingleSet()
{
   final Calendar calendar =
      Calendar.getInstance(TimeZone.getTimeZone(timeZoneId),
         ENGLISH);
   calendar.set(2013, APRIL, 6, 15, 45, 22);
   out.println("Calendar via Constructor: " + stringifyCalendar(calendar));
}
Populating Calendar with Multiple Individual 'set' Methods
/**
 * Demonstrate pre-JDK 8 method of instantiating Calendar instance using
 * individual "set" calls for each pair of field names and values.
 */
public static void demoCalendarWithIndividualSets()
{
   final Calendar calendar =
      Calendar.getInstance(
         TimeZone.getTimeZone(timeZoneId),
         ENGLISH);
   calendar.set(YEAR, 2013);
   calendar.set(MONTH, APRIL);
   calendar.set(DATE, 6);
   calendar.set(HOUR, 3);
   calendar.set(MINUTE, 45);
   calendar.set(SECOND, 22);
   calendar.set(AM_PM, PM);
   out.println("Calendar via set methods: " + stringifyCalendar(calendar));
}

SIDE NOTE: In both of the examples above, I used another increasingly popular feature of modern Java: the static import. The constants such as ENGLISH, YEAR, and SECOND are actually statically imported from classes such as Locale and Calendar. As I have previously written, static imports seem to be increasingly popular with Java developers, especially in light of the trend toward fluent interfaces.

The two "traditional" approaches shown above show different ways to populate the Calendar instance. One extreme is to set each individual field separately while the other is to set all the significant fields with a single "set" method. There are advantages to each approach. The single "set" method has fewer states of an "unfinished" object than the multiple-set approach, but the multiple-set approach is more readable because the name of the value being set is clear based on the first parameter to each "set" method. The single-set approach is a little unwieldy because it takes six integers that can be easily mixed up in order passed because there is no obvious way to differentiate which integer is which other than the implicit order.

Calendar.Builder leverages on the advertised benefits of the Builder as described by Bloch: removes the existence of "inconsistent states partway through [an object's] construction." This is demonstrated in the next code listing.

Calendar.Builder Allows Single-Statement Instantiation with Readable Settings
   /**
    * Demonstrate using JDK 8's Calendar.Builder to instantiate an instance of
    * Calendar using the set methods to set each field individually based on
    * field name and value.
    */
   public static void demoCalendarWithCalendarBuilderSetFields()
   {
      final Calendar calendar =
         new Calendar.Builder()
            .set(YEAR, 2013)
            .set(MONTH, APRIL)
            .set(DATE, 6)
            .set(HOUR, 15)
            .set(MINUTE, 45)
            .set(SECOND, 22)
            .setTimeZone(TimeZone.getTimeZone(timeZoneId))
            .setLocale(ENGLISH)
            .build();
      out.println(
           "Calendar via Calendar.Builder 'set' Fields: "
         + stringifyCalendar(calendar));
   }

In the above code listing, the Calendar instance is created AND populated in one statement, removing the need to risk an object being in an inconsistent state across multiple statements. This example retains the readability of the traditional individual "set" methods approach [set(int, int)] with the added safety of having the object populated fully immediately at instantiation.

For developers who want to provide fewer individual "set" methods, another opportunity with Calendar.Builder is to use the setDate(int, int, int) and setTimeOfDay(int, int, int) methods as demonstrated in the next code listing.

Calendar.Builder Setting Date and Time as Two Calls
/**
 * Demonstrate using JDK 8's Calendar.Builder to instantiate an instance of
 * Calendar using the "setDate" and "setTimeOfDay" builder methods.
 */
public static void demoCalendarWithCalendarBuilderSetDaySetTime()
{
   final Calendar calendar =
      new Calendar.Builder()
         .setDate(2013, APRIL, 6)
         .setTimeOfDay(15, 45, 22)
         .setTimeZone(TimeZone.getTimeZone(timeZoneId))
         .setLocale(ENGLISH).build();
   out.println(
        "Calendar via Calendar.Builder setDate/setTimeOfDay: "
      + stringifyCalendar(calendar));
}

There are fewer characters and lines to type with this approach, but it partially reintroduces the disadvantage of being more likely to have an integer parameter inadvertently switched as each of the two methods takes three integers (or an overloaded version of setTimeOfDay() will take a fourth integer representing milliseconds).

For developers wanting the ultimate flexibility in specifying Calendar parameters during its instantiation, Calendar.Builder provides the method setFields(int ...) that takes an arbitrary length of pairs of integers with the first integer of the pair representing the field to be set and the second integer of the pair representing the value for that field. This method is used in the next code listing.

Specifying Calendar Fields via Calendar.Builder's setFields Method
   /**
    * Demonstrate using JDK 8's Calendar.Builder to instantiate an instance of
    * Calendar using the setFields method that allows providing of Calendar
    * fields as key/value pairs.
    */
   public static void demoCalendarWithCalendarBuilderSetPairs()
   {
      final Calendar calendar =
         new Calendar.Builder()
            .setFields(YEAR, 2013, MONTH, APRIL, DATE, 6, HOUR, 15, MINUTE, 45, SECOND, 22)
            .setTimeZone(TimeZone.getTimeZone("timeZoneId"))
            .setLocale(ENGLISH)
            .build();
      out.println(
           "Calendar via Calendar.Builder setPairs: "
         + stringifyCalendar(calendar));
   }

This setFields(int ...) method brings greater risk of mangling the order of integers used for instantiation of the new instance of Calendar, but using the statically imported Calendar constants does improve readability and reduces the likelihood of mixing the integers incorrectly. If an odd number of integers is provided (meaning that there is an incomplete pair), an IllegalArgumentException is thrown.

Although Calendar.Builder provides some convenience in instantiating and populating an instance of Calendar, anyone fortunate enough to adopt JDK 8 will have access to the new date/time API and so the question might be asked, "Why use Calendar.Builder?" Perhaps the best answer is that there are millions of lines of existing code, libraries, and frameworks out there using and expecting Calendar instances, so it will probably be a long time before the need for Calendar is completely gone (if ever). Fortunately, Calandar.Builder makes it easy to covert an instance of Instant (part of the new Java data/time API) into a Calendar via CalendarBulder.setInstant(long). This is demonstrated in the next code listing.

Converting Instant to Calendar with Calendar.Builder
   /**
    * Demonstrate using JDK 8's Calendar.Builder to instantiate an instance of
    * Calendar based on "now" Instant.
    */
   public static void demoCalendarWithCalendarBuilderInstant()
   {
      final Calendar calendar =
         new Calendar.Builder().setInstant(Instant.now().toEpochMilli())
            .setTimeZone(TimeZone.getTimeZone(timeZoneId))
            .setLocale(ENGLISH)
            .build();
      out.println("Calendar via Calendar.Builder and Instant: " + stringifyCalendar(calendar));
   }

Note that an overloaded version of the setInstant method accepts a Date for instantiating a Calendar. In both cases, whether instantiated with setInstant(long) or setInstant(Date), no other "set" method on Calender.Builder should be called to avoid an IllegalStateException.

It is easy to go the other direction (getting an Instant from a Calendar) using Calendar.toInstant(). Other methods introduced to Calendar with JDK 1.8 are related to providing the current instance's calendar type (as a String) or the set of available calendar types (Set of Strings). When I run Calendar.getAvailableCalendarTypes() on my system, I see these three Strings: "gregory", "japanese", and "buddhist" (the same three calendars documented in Supported Calendars)

Conclusion

Like many Java developers, I'm looking forward to an improved Java data/time API that is built into the standard Java Development Kit. However, I also realize that, especially in large code bases and when using libraries and frameworks expecting Calendar or Date, that I won't be free of Calendar and Date for some time. The introduction of Calendar.Builder in JDK 8 eases that burden a bit.