Showing posts with label J2SE 5. Show all posts
Showing posts with label J2SE 5. Show all posts

Saturday, May 26, 2018

Java's String.format Can Be Statically Imported

JDK-8203630 ["Add instance method equivalents for String::format"] postulates that "the argument for implementing String::format as static appears to be that the format methods could be imported statically and thus conduct themselves comparably to C's sprintf." On a StackOverflow.com thread on the subject, Brandon Yarbrough writes, "by making the method static you can use format in a way that's very familiar and clean-looking to C programmers used to printf()." Yarbrough provides a code example and then concludes, "By using static imports, printfs look almost exactly like they do in C. Awesome!"

When I read in JDK-8203630 about this, I wondered to myself why I had not statically imported String.format when I've used it because it seems obvious to me now to do that. In this post, I look briefly at some personal theories I have considered to explain why I (and many others apparently) have not thought to statically import String.format consistently.

When static imports were introduced with J2SE 5, the new documentation on the feature presented the question, "So when should you use static import?" It answered its own question with an emphasized (I did NOT add the bold), "Very sparingly!" That paragraph then goes on to provide more details about appropriate and inappropriate uses of static imports and the negative consequences of overuse of static imports.

Although the original documentation warned emphatically about the overuse of static imports, their use did seem to increase gradually as developers became more used to them. In 2012, I asked, via blog post, "Are Static Imports Becoming Increasingly Accepted in Java?" I felt at that time that they were becoming increasingly accepted, especially when used in unit testing contexts and in more modern libraries and frameworks focusing on providing "fluent" APIs. Still, somehow, I did not think to consistently apply static imports to my uses of String.format.

I don't use String.format very often, so I thought that perhaps I just didn't get many opportunities to think about this. But, even in my relatively few uses of it, I don't recall ever importing it statically. As I've thought about this more, I've realized that the primary reason I probably don't think about statically importing String.format is the same reason that most developers have not thought about it: most of the popular and readily available online examples of how to use String.format do not use static imports!

When writing a blog or article covering a feature, especially if it's at an introductory level, it can be useful to NOT do things like import statically because the explicitly spelling out of the class name can improve the developer's ability to understand where the methods in the code come from. However, this also means that if a given developer reads numerous articles and posts and none of them show use of static imports, it is easy for that developer to use the API as shown in all those examples without thinking about the possibility of statically importing.

The following are some introductory posts regarding use of String.format. At the time of this writing, they do not demonstrate use of String.format via static import. I want to emphasize that this does not take away from the quality of these resources; in fact, some of them are excellent. This is instead intended as evidence explaining why String.format seems to be seldom statically imported in Java code.

Many of the examples in the above posts use String.format() to generate a String that is assigned to a local variable. In this context, the static import is arguably less valuable than when it is used to format a String within a greater line of code. For example, it is more "fluent" to statically import String.format() so that simply format() can be specified when that formatting takes place in a line of code doing other things beyond simply assigning the formatted string to a local variable.

The main purpose of this blog post is to point out/remind us that we can statically import String.format when doing so makes our code more readable. However, there were some other interesting points made in the short discussion on the OpenJDK core-libs-dev mailing list on this subject that I'll briefly point out here:

  • JDK-8203630 points out how an instance method might make for arguably more readable code in some cases with this example: "This result is %d".format(result);
  • RĂ©mi Forax points out some arguments against adding an instance format method to String:
    • Issues associated with static and instance methods sharing the same name in a class.
      • John Rose adds, "Refactoring static as non-static methods, or vice versa, is a very reasonable design move, but the language makes it hard to do this and retain backward compatibility."
    • Relative slowness of Java's current string interpolation capabilities with provided by String.format
    • Potential of StringConcatFactory for future faster Java string interpolation (see "String concatenation in Java 9 (part 1): Untangling invokeDynamic" for more details on StringConcatFactory).

Whether or not instance format methods come to Java's String, reading about JDK-8203444, JDK-8203630, and the associated mailing list discussion have provided me with some things to think about. If nothing else, I'll definitely be more apt to weigh String.format's performance when considering using it and will be more likely to statically import it when I do use it.

Friday, August 15, 2014

Autoboxing, Unboxing, and NoSuchMethodError

J2SE 5 introduced numerous features to the Java programming language. One of these features is autoboxing and unboxing, a feature that I use almost daily without even thinking about it. It is often convenient (especially when used with collections), but every once in a while it leads to some nasty surprises, "weirdness," and "madness." In this blog post, I look at a rare (but interesting to me) case of NoSuchMethodError resulting from mixing classes compiled with Java versions before autoboxing/unboxing with classes compiled with Java versions that include autoboxing/unboxing.

The next code listing shows a simple Sum class that could have been written before J2SE 5. It has overloaded "add" methods that accept different primitive numeric data types and each instance of Sum> simply adds all types of numbers provided to it via any of its overloaded "add" methods.

Sum.java (pre-J2SE 5 Version)
import java.util.ArrayList;

public class Sum
{
   private double sum = 0;

   public void add(short newShort)
   {
      sum += newShort;
   }

   public void add(int newInteger)
   {
      sum += newInteger;
   }

   public void add(long newLong)
   {
      sum += newLong;
   }

   public void add(float newFloat)
   {
      sum += newFloat;
   }

   public void add(double newDouble)
   {
      sum += newDouble;
   }

   public String toString()
   {
      return String.valueOf(sum);
   }
}

Before unboxing was available, any clients of the above Sum class would need to provide primitives to these "add" methods or, if they had reference equivalents of the primitives, would need to convert the references to their primitive counterparts before calling one of the "add" methods. The onus was on the client code to do this conversion from reference type to corresponding primitive type before calling these methods. Examples of how this might be accomplished are shown in the next code listing.

No Unboxing: Client Converting References to Primitives
private static String sumReferences(
   final Long longValue, final Integer intValue, final Short shortValue)
{
   final Sum sum = new Sum();
   if (longValue != null)
   {
      sum.add(longValue.longValue());
   }
   if (intValue != null)
   {
      sum.add(intValue.intValue());
   }
   if (shortValue != null)
   {
      sum.add(shortValue.shortValue());
   }
   return sum.toString();
}

J2SE 5's autoboxing and unboxing feature was intended to address this extraneous effort required in a case like this. With unboxing, client code could call the above "add" methods with references types corresponding to the expected primitive types and the references would be automatically "unboxed" to the primitive form so that the appropriate "add" methods could be invoked. Section 5.1.8 ("Unboxing Conversion") of The Java Language Specification explains which primitives the supplied numeric reference types are converted to in unboxing and Section 5.1.7 ("Boxing Conversion") of that same specification lists the references types that are autoboxed from each primitive in autoboxing.

In this example, unboxing reduced effort on the client's part in terms of converting reference types to their corresponding primitive counterparts before calling Sum's "add" methods, but it did not completely free the client from needing to process the number values before providing them. Because reference types can be null, it is possible for a client to provide a null reference to one of Sum's "add" methods and, when Java attempts to automatically unbox that null to its corresponding primitive, a NullPointerException is thrown. The next code listing adapts that from above to indicate how the conversion of reference to primitive is no longer necessary on the client side but checking for null is still necessary to avoid the NullPointerException.

Unboxing Automatically Coverts Reference to Primitive: Still Must Check for Null
private static String sumReferences(
   final Long longValue, final Integer intValue, final Short shortValue)
{
   final Sum sum = new Sum();
   if (longValue != null)
   {
      sum.add(longValue);
   }
   if (intValue != null)
   {
      sum.add(intValue);
   }
   if (shortValue != null)
   {
      sum.add(shortValue);
   }
   return sum.toString();
}

Requiring client code to check their references for null before calling the "add" methods on Sum may be something we want to avoid when designing our API. One way to remove that need is to change the "add" methods to explicitly accept the reference types rather than the primitive types. Then, the Sum class could check for null before explicitly or implicitly (unboxing) dereferencing it. The revised Sum class with this changed and more client-friendly API is shown next.

Sum Class with "add" Methods Expecting References Rather than Primitives
import java.util.ArrayList;

public class Sum
{
   private double sum = 0;

   public void add(Short newShort)
   {
      if (newShort != null)
      {
         sum += newShort;
      }
   }

   public void add(Integer newInteger)
   {
      if (newInteger != null)
      {
         sum += newInteger;
      }
   }

   public void add(Long newLong)
   {
      if (newLong != null)
      {
         sum += newLong;
      }
   }

   public void add(Float newFloat)
   {
      if (newFloat != null)
      {
         sum += newFloat;
      }
   }

   public void add(Double newDouble)
   {
      if (newDouble != null)
      {
         sum += newDouble;
      }
   }

   public String toString()
   {
      return String.valueOf(sum);
   }
}

The revised Sum class is more client-friendly because it allows the client to pass a reference to any of its "add" methods without concern for whether the passed-in reference is null or not. However, the change of the Sum class's API like this can lead to NoSuchMethodErrors if either class involved (the client class or one of the versions of the Sum class) is compiled with different versions of Java. In particular, if the client code uses primitives and is compiled with JDK 1.4 or earlier and the Sum class is the latest version shown (expecting references instead of primitives) and is compiled with J2SE 5 or later, a NoSuchMethodError like the following will be encountered (the "S" indicates it was the "add" method expecting a primitive short and the "V" indicates that method returned void).

Exception in thread "main" java.lang.NoSuchMethodError: Sum.add(S)V
 at Main.main(Main.java:9)

On the other hand, if the client is compiled with J2SE 5 or later and with primitive values being supplied to Sum as in the first example (pre-unboxing) and the Sum class is compiled in JDK 1.4 or earlier with "add" methods expecting primitives, a different version of the NoSuchMethodError is encountered. Note that the Short reference is cited here.

Exception in thread "main" java.lang.NoSuchMethodError: Sum.add(Ljava/lang/Short;)V
 at Main.main(Main.java:9)

There are several observations and reminders to Java developers that come from this.

  • Classpaths are important:
    • Java .class files compiled with the same version of Java (same -source and -target) would have avoided the particular problem in this post.
    • Classpaths should be as lean as possible to reduce/avoid possibility of getting stray "old" class definitions.
    • Build "clean" targets and other build operations should be sure to clean past artifacts thoroughly and builds should rebuild all necessary application classes.
  • Autoboxing and Unboxing are well-intentioned and often highly convenient, but can lead to surprising issues if not kept in mind to some degree. In this post, the need to still check for null (or know that the object is non-null) is necessary remains in situations when implicit dereferencing will take place as a result of unboxing.
  • It's a matter of API style taste whether to allow clients to pass nulls and have the serving class check for null on their behalf. In an industrial application, I would have stated whether null was allowed or not for each "add" method parameter with @param in each method's Javadoc comment. In other situations, one might want to leave it the responsibility of the caller to ensure any passed-in reference is non-null and would be content throwing a NullPointerException if the caller did not obey that contract (which should also be specified in the method's Javadoc).
  • Although we typically see NoSuchMethodError when a method is completely removed or when we access an old class before that method was available or when a method's API has changed in terms of types or number of types. In a day when Java autoboxing and unboxing are largely taken for granted, it can be easy to think that changing a method from taking a primitive to taking the corresponding reference type won't affect anything, but even that change can lead to an exception if not all classes involved are built on a version of Java supporting autoboxing and unboxing.
  • One way to determine the version of Java against which a particular .class file was compiled is to use javap -verbose and to look in the javap output for the "major version:". In the classes I used in my examples in this post (compiled against JDK 1.4 and Java SE 8), the "major version" entries were 48 and 52 respectively (the General Layout section of the Wikipedia entry on Java class file lists the major versions).

Fortunately, the issue demonstrated with examples and text in this post is not that common thanks to builds typically cleaning all artifacts and rebuilding code on a relatively continuous basis. However, there are cases where this could occur and one of the most likely such situations is when using an old JAR file accidentally because it lies in wait on the runtime classpath.

Tuesday, July 12, 2011

Use == (or !=) to Compare Java Enums

Most new Java developers quickly learn that they should generally compare Java Strings using String.equals(Object) rather than using ==. This is emphasized and reinforced to new developers repeatedly because they almost always mean to compare String content (the actual characters forming the String) rather than the String's identity (its address in memory). I contend that we should reinforce the notion that == can be used instead of Enum.equals(Object). I provide my reasoning for this assertion in the remainder of this post.

There are four reasons that I believe using == to compare Java enums is almost always preferable to using the "equals" method:
  1. The == on enums provides the same expected comparison (content) as equals
  2. The == on enums is arguably more readable (less verbose) than equals
  3. The == on enums is more null-safe than equals
  4. The == on enums provides compile-time (static) checking rather than runtime checking

The second reason listed above ("arguably more readable") is obviously a matter of opinion, but that part about "less verbose" can be agreed upon. The first reason I generally prefer == when comparing enums is a consequence of how the Java Language Specification describes enums. Section 8.9 ("Enums") states:
It is a compile-time error to attempt to explicitly instantiate an enum type. The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.

Because there is only one instance of each enum constant, it is permissible to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant. (The equals method in Enum is a final method that merely invokes super.equals on its argument and returns the result, thus performing an identity comparison.)

The excerpt from the specification shown above implies and then explicitly states that it is safe to use the == operator to compare two enums because there is no way that there can be more than one instance of the same enum constant.

The fourth advantage to == over .equals when comparing enums has to do with compile-time safety. The use of == forces a stricter compile time check than that for .equals because Object.equals(Object) must, by contract, take an arbitrary Object. When using a statically typed language such as Java, I believe in taking advantage of the advantages of this static typing as much as possible. Otherwise, I'd use a dynamically typed language. I believe that one of the recurring themes of Effective Java is just that: prefer static type checking whenever possible.

For example, suppose I had a custom enum called Fruit and I tried to compare it to the class java.awt.Color. Using the == operator allows me to get a compile-time error (including advance notice in my favorite Java IDE) of the problem. Here is a code listing that tries to compare a custom enum to a JDK class using the == operator:

/**
    * Indicate if provided Color is a watermelon.
    *
    * This method's implementation is commented out to avoid a compiler error
    * that legitimately disallows == to compare two objects that are not and
    * cannot be the same thing ever.
    *
    * @param candidateColor Color that will never be a watermelon.
    * @return Should never be true.
    */
   public boolean isColorWatermelon(java.awt.Color candidateColor)
   {
      // This comparison of Fruit to Color will lead to compiler error:
      //    error: incomparable types: Fruit and Color
      return Fruit.WATERMELON == candidateColor;
   }

The compiler error is shown in the screen snapshot that comes next.


Although I'm no fan of errors, I prefer them to be caught statically at compile time rather than depending on runtime coverage. Had I used the equals method for this comparison, the code would have compiled fine, but the method would always return false false because there is no way a dustin.examples.Fruit enum will be equal to a java.awt.Color class. I don't recommend it, but here is the comparison method using .equals:

/**
    * Indicate whether provided Color is a Raspberry. This is utter nonsense
    * because a Color can never be equal to a Fruit, but the compiler allows this
    * check and only a runtime determination can indicate that they are not
    * equal even though they can never be equal. This is how NOT to do things.
    *
    * @param candidateColor Color that will never be a raspberry.
    * @return {@code false}. Always.
    */
   public boolean isColorRaspberry(java.awt.Color candidateColor)
   {
      //
      // DON'T DO THIS: Waste of effort and misleading code!!!!!!!!
      //
      return Fruit.RASPBERRY.equals(candidateColor);
   }

The "nice" thing about the above is the lack of compile-time errors. It compiles beautifully. Unfortunately, this is paid for with a potentially high price.

The final advantage I listed of using == rather than Enum.equals when comparing enums is the avoidance of the dreaded NullPointerException. As I stated in Effective Java NullPointerException Handling, I generally like to avoid unexpected NullPointerExceptions. There is a limited set of situations in which I truly want the existence of a null to be treated as an exceptional case, but often I prefer a more graceful reporting of a problem. An advantage of comparing enums with == is that a null can be compared to a non-null enum without encountering a NullPointerException (NPE). The result of this comparison, obviously, is false.

One way to avoid the NPE when using .equals(Object) is to invoke the equals method against an enum constant or a known non-null enum and then pass the potential enum of questionable character (possibly null) as a parameter to the equals method. This has often been done for years in Java with Strings to avoid the NPE. However, with the == operator, order of comparison does not matter. I like that.

I've made my arguments and now I move onto some code examples. The next listing is a realization of the hypothetical Fruit enum mentioned earlier.

Fruit.java
package dustin.examples;

public enum Fruit
{
   APPLE,
   BANANA,
   BLACKBERRY,
   BLUEBERRY,
   CHERRY,
   GRAPE,
   KIWI,
   MANGO,
   ORANGE,
   RASPBERRY,
   STRAWBERRY,
   TOMATO,
   WATERMELON
}

The next code listing is a simple Java class that provides methods for detecting if a particular enum or object is a certain fruit. I'd normally put checks like these in the enum itself, but they work better in a separate class here for my illustrative and demonstrative purposes. This class includes the two methods shown earlier for comparing Fruit to Color with both == and equals. Of course, the method using == to compare an enum to a class had to have that part commented out to compile properly.

EnumComparisonMain.java
package dustin.examples;

public class EnumComparisonMain
{
   /**
    * Indicate whether provided fruit is a watermelon ({@code true} or not
    * ({@code false}).
    * 
    * @param candidateFruit Fruit that may or may not be a watermelon; null is
    *    perfectly acceptable (bring it on!).
    * @return {@code true} if provided fruit is watermelon; {@code false} if
    *    provided fruit is NOT a watermelon.
    */
   public boolean isFruitWatermelon(Fruit candidateFruit)
   {
      return candidateFruit == Fruit.WATERMELON;
   }

   /**
    * Indicate whether provided object is a Fruit.WATERMELON ({@code true}) or
    * not ({@code false}).
    *
    * @param candidateObject Object that may or may not be a watermelon and may
    *    not even be a Fruit!
    * @return {@code true} if provided object is a Fruit.WATERMELON;
    *    {@code false} if provided object is not Fruit.WATERMELON.
    */
   public boolean isObjectWatermelon(Object candidateObject)
   {
      return candidateObject == Fruit.WATERMELON;
   }

   /**
    * Indicate if provided Color is a watermelon.
    *
    * This method's implementation is commented out to avoid a compiler error
    * that legitimately disallows == to compare two objects that are not and
    * cannot be the same thing ever.
    *
    * @param candidateColor Color that will never be a watermelon.
    * @return Should never be true.
    */
   public boolean isColorWatermelon(java.awt.Color candidateColor)
   {
      // Had to comment out comparison of Fruit to Color to avoid compiler error:
      //    error: incomparable types: Fruit and Color
      return /*Fruit.WATERMELON == candidateColor*/ false;
   }

   /**
    * Indicate whether provided fruit is a strawberry ({@code true}) or not
    * ({@code false}).
    *
    * @param candidateFruit Fruit that may or may not be a strawberry; null is
    *    perfectly acceptable (bring it on!).
    * @return {@code true} if provided fruit is strawberry; {@code false} if
    *    provided fruit is NOT strawberry.
    */
   public boolean isFruitStrawberry(Fruit candidateFruit)
   {
      return Fruit.STRAWBERRY == candidateFruit;
   }

   /**
    * Indicate whether provided fruit is a raspberry ({@code true}) or not
    * ({@code false}).
    *
    * @param candidateFruit Fruit that may or may not be a raspberry; null is
    *    completely and entirely unacceptable; please don't pass null, please,
    *    please, please.
    * @return {@code true} if provided fruit is raspberry; {@code false} if
    *    provided fruit is NOT raspberry.
    */
   public boolean isFruitRaspberry(Fruit candidateFruit)
   {
      return candidateFruit.equals(Fruit.RASPBERRY);
   }

   /**
    * Indicate whether provided Object is a Fruit.RASPBERRY ({@code true}) or
    * not ({@code false}).
    *
    * @param candidateObject Object that may or may not be a Raspberry and may
    *    or may not even be a Fruit!
    * @return {@code true} if provided Object is a Fruit.RASPBERRY; {@code false}
    *    if it is not a Fruit or not a raspberry.
    */
   public boolean isObjectRaspberry(Object candidateObject)
   {
      return candidateObject.equals(Fruit.RASPBERRY);
   }

   /**
    * Indicate whether provided Color is a Raspberry. This is utter nonsense
    * because a Color can never be equal to a Fruit, but the compiler allows this
    * check and only a runtime determination can indicate that they are not
    * equal even though they can never be equal. This is how NOT to do things.
    *
    * @param candidateColor Color that will never be a raspberry.
    * @return {@code false}. Always.
    */
   public boolean isColorRaspberry(java.awt.Color candidateColor)
   {
      //
      // DON'T DO THIS: Waste of effort and misleading code!!!!!!!!
      //
      return Fruit.RASPBERRY.equals(candidateColor);
   }

   /**
    * Indicate whether provided fruit is a grape ({@code true}) or not
    * ({@code false}).
    *
    * @param candidateFruit Fruit that may or may not be a grape; null is
    *    perfectly acceptable (bring it on!).
    * @return {@code true} if provided fruit is a grape; {@code false} if
    *    provided fruit is NOT a grape.
    */
   public boolean isFruitGrape(Fruit candidateFruit)
   {
      return Fruit.GRAPE.equals(candidateFruit);
   }
}

I decided to approach demonstration of the ideas captured in the above methods via unit tests. In particular, I make use of Groovy's GroovyTestCase. That class for using Groovy-powered unit testing is in the next code listing.

EnumComparisonTest.groovy
package dustin.examples

class EnumComparisonTest extends GroovyTestCase
{
   private EnumComparisonMain instance

   void setUp() {instance = new EnumComparisonMain()}

   /**
    * Demonstrate that while null is not watermelon, this check does not lead to
    * NPE because watermelon check uses {@code ==} rather than {@code .equals}.
    */
   void testIsWatermelonIsNotNull()
   {
      assertEquals("Null cannot be watermelon", false, instance.isFruitWatermelon(null))
   }

   /**
    * Demonstrate that a passed-in Object that is really a disguised Fruit can
    * be compared to the enum and found to be equal.
    */
   void testIsWatermelonDisguisedAsObjectStillWatermelon()
   {
      assertEquals("Object should have been watermelon",
                   true, instance.isObjectWatermelon(Fruit.WATERMELON))
   }

   /**
    * Demonstrate that a passed-in Object that is really a disguised Fruit can
    * be compared to the enum and found to be not equal.
    */
   void testIsOtherFruitDisguisedAsObjectNotWatermelon()
   {
      assertEquals("Fruit disguised as Object should NOT be watermelon",
                   false, instance.isObjectWatermelon(Fruit.ORANGE))
   }

   /**
    * Demonstrate that a passed-in Object that is really a null can be compared
    * without NPE to the enum and that they will be considered not equal.
    */
   void testIsNullObjectNotEqualToWatermelonWithoutNPE()
   {
      assertEquals("Null, even as Object, is not equal to Watermelon",
                   false, instance.isObjectWatermelon(null))
   }

   /** Demonstrate that test works when provided fruit is indeed watermelon. */
   void testIsWatermelonAWatermelon()
   {
      assertEquals("Watermelon expected for fruit", true, instance.isFruitWatermelon(Fruit.WATERMELON))
   }

   /** Demonstrate that fruit other than watermelon is not a watermelon. */
   void testIsWatermelonBanana()
   {
      assertEquals("A banana is not a watermelon", false, instance.isFruitWatermelon(Fruit.BANANA))
   }

   /**
    * Demonstrate that while null is not strawberry, this check does not lead to
    * NPE because strawberry check uses {@code ==} rather than {@code .equals}.
    */
   void testIsStrawberryIsNotNull()
   {
      assertEquals("Null cannot be strawberry", false, instance.isFruitStrawberry(null))
   }

   /**
    * Demonstrate that raspberry case throws NPE because of attempt to invoke
    * {@code .equals} method on null.
    */
   void testIsFruitRaspberryThrowsNpeForNull()
   {
      shouldFail(NullPointerException)
      {
         instance.isFruitRaspberry(null)
      }
   }

   /**
    * Demonstrate that raspberry case throws NPE even for Object because of
    * attempt to invoke {@code .equals} method on null.
    */
   void testIsObjectRaspberryThrowsNpeForNull()
   {
      shouldFail(NullPointerException)
      {
         instance.isObjectRaspberry(null)
      }
   }

   /**
    * Demonstrate that {@code .equals} approach works for comparing enums even if
    * {@code .equals} is invoked on passed-in object.
    */
   void testIsRaspberryDisguisedAsObjectRaspberry()
   {
      assertEquals("Expected object to be raspberry",
                   true, instance.isObjectRaspberry(Fruit.RASPBERRY))
   }

   /**
    * Demonstrate that while null is not grape, this check does not lead to NPE
    * because grape check invokes {@code .equals} method on the enum constant
    * being compared rather than on the provided {@code null}.
    */
   void testIsGrapeIsNotNull()
   {
      assertEquals("Null cannot be grape", false, instance.isFruitGrape(null))
   }
}

I don't describe what the various tests demonstrate much here because the comments on the tested class's methods and on the test methods cover most of that. In short, the variety of tests demonstrate that == is null-safe, and that equals is not null safe unless invoked on an enum constant or known non-null enum. There are a few other tests to ensure that the comparisons work as we'd expect them to work. The output from running the unit tests is shown next.


The GroovyTestCase method shouldFail reported that an NPE was indeed thrown when code attempted to call equals on an advertised enum that was really null. Because I used the overloaded version of this method that accepted the excepted exception as a parameter, I was able to ensure that it was an NPE that was thrown. The next screen snapshot shows what I would have seen if I had told the unit test that an IllegalArgumentException was expected rather than a NullPointerException.


I'm not the only one who thinks that == is preferable to equals when comparing enums. After I started writing this (because I saw what I deem to be a misuse of equals for comparing two enums again today for the umpteeth time), I discovered other posts making the same argument. The post == or equals with Java enum highlights the compile-time advantage of explicitly comparing two distinct types with ==: "Using == the compiler screams and tells us that we are comparing apples with oranges." Ashutosh's post Comparing Java Enums concludes that "using == over .equals() is more advantageous in two ways" (avoiding the NPE and getting the static compile-time check). The latter post also pointed me to the excellent reference Comparing Java enum members: == or equals()?.


The Dissenting View

All three references just mentioned had dissenting opinions either in the thread (the last reference) or as comments to the blog post (the first two references). The primary arguments for comparing enums with equals rather than == is consistency with comparing of other reference types (non-primitives). There is also an argument that equals is in a way more readable because a less experienced Java developer won't think it is wrong and he or she might think == is a bad idea. My argument to that is that it is good to know the difference and could provide a valuable teaching experience. Another argument against == is that equals gets compiled into the == form anyway. I don't see that so much as an argument against using ==. In fact, it really is a moot point in my mind if they are the same thing in byte code anyway. Furthermore, it doesn't take away from the advantages of == in terms of null safety and static type checking.


Don't Forget !=

All of the above arguments apply to the question of != versus !Enum.equals(Object), of course. The Java Tutorials section Getting and Setting Fields with Enum Types demonstrates comparing the same enum types and their example makes use of !=.


Conclusion

There is very little in software development that can be stated unequivocally and without controversy. The use of equals versus == for comparing enums is no exception to this. However, I have no problem comparing primitives in Java (as long as I ensure they are true primitives and not unboxed references) with == and likewise have no problem comparing enums with == either. The specification explicitly spells out that this is permissible as does the Java Tutorials (which uses != rather than !Enum.equals). I actually go further than that and state that it is preferable. If I can avoid NullPointerExceptions and still get the response I want (two compared things are not equal) and can move my error checking up to compile time all without extra effort, I'll take that deal just about every time.

Saturday, April 30, 2011

The Highly Useful Java TimeUnit Enum

Although it is part of the java.util.concurrent package, the TimeUnit enum is useful in many contexts outside of concurrency. In this post, I look at how the TimeUnit enum can be used even in code that does not directly deal with concurrent functionality before examining how this enum is an example of many broader concepts in Java development.

Most of us who have probably seen (or implemented, but we'll blame the other developer for it now) code like that shown in the next code listing. In this code listing, a number of provided milliseconds is converted to a whole number of days by dividing by a previously determined single hard-coded number (86400000, the number of milliseconds in one day).

   /**
    * Convert provided number of milliseconds into number of days.
    *
    * @param numberMilliseconds Number of milliseconds to be converted into days.
    * @return Number of days corresponding to number of provided milliseconds.
    */
   private static long convertMilliSecondsToDaysViaSingleMagicNumber(final long numberMilliseconds)
   {
      // 86400000 = 86400 seconds in a day multipled by 1000 ms per second
      return numberMilliseconds / 86400000;
   }

There are some problems with the approach taken by the above code listing. The most obvious issue may be the use of the magic number 86400000. Although most of us recognize 86400 as the number of seconds in a day, this may not be obvious to everyone and then there's the issue of it being 1000 times greater than that number. The comment in the code listing helps by explaining the underlying meaning of the numbers, but wouldn't it be nice if the code spoke more clearly for itself?

The next code listing shows an arguable slight improvement. Rather than using a single hard-coded number, individual hard-coded numbers are used that are more readable because they are separate. A reader of the code has a better chance of seeing how the number was constructed.

   /**
    * Convert provided number of milliseconds into number of days.
    *
    * @param numberMilliseconds Number of milliseconds to be converted into days.
    * @return Number of days corresponding to number of provided milliseconds.
    */
   private static long convertMilliSecondsToDaysViaMoreExplanatoryMagicNumbers(final long numberMilliseconds)
   {
      // 60 seconds in minute, 60 minutes in hour, 24 hours in day, and
      // one thousand milliseconds in a second
      return numberMilliseconds / (60 * 60 * 24 * 1000);
   }

Even though the individual numbers might make it easier to see what's happening in the conversion, the comment still might be useful in ensuring that the proper function is understood well. Magic numbers are also still involved and most code analysis tools will report issues with their use. The next code example attempts to deal with the issue of magic numbers.

   private final static int NUMBER_MILLISECONDS_IN_SECOND = 1000;
   private final static int NUMBER_SECONDS_IN_MINUTE = 60; 
   private final static int NUMBER_MINUTES_IN_HOUR = 60;
   private final static int NUMBER_SECONDS_IN_HOUR =
      NUMBER_SECONDS_IN_MINUTE * NUMBER_MINUTES_IN_HOUR;
   private final static int NUMBER_HOURS_IN_DAY = 24;
   private final static int NUMBER_MINUTES_IN_DAY =
      NUMBER_HOURS_IN_DAY * NUMBER_MINUTES_IN_HOUR;
   private final static int NUMBER_SECONDS_IN_DAY =
      NUMBER_HOURS_IN_DAY * NUMBER_SECONDS_IN_HOUR;
   private final static int NUMBER_MILLISECONDS_IN_DAY =
      NUMBER_SECONDS_IN_DAY * NUMBER_MILLISECONDS_IN_SECOND;

   /**
    * Convert provided number of milliseconds into number of days.
    *
    * @param numberMilliseconds Number of milliseconds to be converted into days.
    * @return Number of days corresponding to number of provided milliseconds.
    */
   private static long convertMilliSecondsToDaysViaDefinedConstant(final long numberMilliseconds)
   {
      return numberMilliseconds / NUMBER_MILLISECONDS_IN_DAY;
   }

The approach in the code above is commonly seen in Java code. The "magic" numbers are now defined as constants that can be reused in more than just one place. Although this is arguably an improvement, TimeUnit allows us to make a further improvement to this code.

   /**
    * Convert provided number of milliseconds into number of days.
    *
    * @param numberMilliseconds Number of milliseconds to be converted into days.
    * @return Number of days corresponding to number of provided milliseconds.
    */
   private static long convertMillisecondsToDaysViaTimeUnit(final long numberMilliseconds)
   {
      return TimeUnit.MILLISECONDS.toDays(numberMilliseconds);
   }

This code takes advantage of TimeUnit's MILLISECONDS enum constant and toDays(long) method to easily perform this conversion is a standardized and highly readable way. There isn't a magic number in sight!

The above example demonstrates how TimeUnit can be used even when concurrency is not involved. Besides MILLISECONDS, other time unit representations provided by TimeUnit include DAYS, HOURS, MICROSECONDS, MINUTES, NANOSECONDS, and SECONDS. These cover the most commonly used time units one would need.

The methods on the TimeUnit enum allow easy conversion from the unit represented by the enum constant to a different unit of time. There is a general conversion method TimeUnit.convert(long, TimeUnit) that can be used for this purpose. More specific methods are also available for converting to specific types of time units so that the second parameter need not be applied. These methods include the already demonstrated toDays(long) as well as toHours(long), toMicros(long), toMillis(long), toMinutes(long), toNanos(long), and toSeconds(long). Although most of this enum was introduced with J2SE 5, the methods toMinutes(long), toHours(long), and toDays(long) were introduced with Java SE 6.

The enum constants and methods on TimeUnit defined so far are not specifically associated with concurrency and are generally useful. The TimeUnit enum offers three additional methods of interest. TimeUnit.sleep(long) provides a more readable Thread.sleep(long, int). The enum constant of the TimeUnit implies the applicable unit of time, so only a base number needs to be provided. The implication here, of course, is that more obvious numbers can be provided for sleeping rather than needing to worry about expressing a large number in milliseconds or even remembering that the method requires the time be specified in milliseconds.

Two other related useful methods available in TimeUnit are TimeUnit.timedJoin(Thread,long) [convenience method for Thread.join] and TimeUnit.timedWait(Thread,long) [convenience method for Object.wait].

I have used this post to demonstrate how TimeUnit is most obviously useful: it helps developers to write clear code without use of magic numbers for converting between different time measurement units. This is handy in its own right because different APIs often expect different time units. However, TimeUnit has benefits beyond its obvious intended functionality benefits. The TimeUnit enum shows off the power of Java enums and how this power can be leveraged. I look at this next.

Most of us who transitioned from C++ to Java missed having an enum in versions of Java prior to J2SE 5. Fortunately, the wait was worth it as the Java enum is far superior to the C++ enum. There are numerous ways in which the Java enum is better than the C++ enum, but one of the main advantages is the ability to implement methods on the enum. This was shown in the above example where a toDays(long) method allowed for easy conversion of milliseconds via the MILLISECONDS.toDays(long) call. A Java enum is much more than simply an encapsulation of a finite set of integral values. The ability to add behaviors to these enum constants is very powerful.

There are two main approaches for defining methods on an enum. One approach is to define a method at the overall enum level and override it individually at each enum constant's level. The other approach is to implement the method once for the entire enum and all of its enum constants with no need to override the single definition. In other words, one approach is to write an implementation of a method for each enum constant and the other approach writes a method that all the enum constants share. The TimeUnit enum demonstrates both approaches. Its general convert method and all of the convenient toXXXXX methods (where XXXXX are things like Hours or Days) are written specifically for each enum constant and the parent method at the overall enum level throws an AbstractMethodError if not properly overridden by each enum constant (fortunately it always is!). The remaining public methods (timedWait, timedJoin, and sleep) are written with the second approach: a single method implementation exists for each of these that is used by any enum constant defined for TimeUnit.

Besides its usefulness in providing highly readable time unit conversions and besides its usefulness in demonstrating the significant advantages of the Java enum, TimeUnit provides an example of one other "often true" principle in Java: highly and generally useful classes (or enum in this case) can often be found in the SDK where you might least expect it. Although the usefulness of TimeUnit is obvious in concurrent applications, its usefulness goes beyond concurrent functionality. This is not the only case where a more generally useful construct is available in the JDK in a more particular package. I have often seen this in projects I've worked on as well. Often a team will put together a nice class or enum for their own use that is more generally applicable, but which ends up remaining in their rather particular package instead of being in a more generally accessible package.

When we build our own time conversion routines, we typically see hard-coded numbers (or constants defined as) with values such as 1000, 60, and 24. So, it is not surprising that the source code for TimeUnit defines these as constants that it uses in its own conversions. Eventually, the rubber must hit the road and these conversions must take place with these hard numbers. The difference is that use of TimeUnit allows us to have those numbers defined and used outside of our direct code in a well-tested and standardly available enum. It is also interesting to note that hard-coded integers were used in early versions of TimeUnit, but were eventually replaced with internally defined constants:
// Handy constants for conversion methods
static final long C0 = 1L;
static final long C1 = C0 * 1000L;
static final long C2 = C1 * 1000L;
static final long C3 = C2 * 1000L;
static final long C4 = C3 * 60L;
static final long C5 = C4 * 60L;
static final long C6 = C5 * 24L;

This post has been lengthy already, but I'd like to stuff one more thing in. This is a simple Groovy script that uses TimeUnit to demonstrate how many hours, minutes, seconds, milliseconds, microseconds, and nanoseconds are in a single day.

showTimeUnitConversionFactors.groovy
#!/usr/bin/env groovy
// showTimeUnitConversionFactors.groovy
import java.util.concurrent.TimeUnit
println "IN A SINGLE DAY"
println "\tHours:   ${TimeUnit.DAYS.toHours(1)}"
println "\tMinutes: ${TimeUnit.DAYS.toMinutes(1)}"
println "\tSeconds: ${TimeUnit.DAYS.toSeconds(1)}"
println "\tMilliseconds: ${TimeUnit.DAYS.toMillis(1)}"
println "\tMicroseconds: ${TimeUnit.DAYS.toMicros(1)}"
println "\tNanoseconds:  ${TimeUnit.DAYS.toNanos(1)}"

The output of running this Groovy script is shown next:



Conclusion

The TimeUnit enum is obviously useful for converting between units of time in a highly readable and standardized approach. Its value goes beyond that, however, because this SDK enum is an example of the power of the Java enum and demonstrates multiple ways to harness that power.


Additional Resources

There are several other really insightful blog posts regarding TimeUnit. These include The usefulness of java.util.concurrent.TimeUnit, Java TimeUnit: More than just a unit of time, Finding the difference between two dates in Java, and Time Unit Conversion in Java.

Tuesday, June 3, 2008

The Power and Flexibility of the Java Enum

As I learned and first worked with Java, I missed not having an enum like I had become used to in C++. However, when Java finally introduced the enum in J2SE 5, the result was worth the wait. In this blog entry, I'm going to cover some of the things that I really like about the enum because I have been surprised at how many experienced Java developers don't fully appreciate their power and flexibility.

For my first example, I'll demonstrate that the Java Enum is really a Java class that extends Object like other Java classes. This is most easily demonstrated by overriding the toString method of one of the enum's values.

PlainOldEnum.java

public enum PlainOldEnum
{
VANILLA,
BORING,
BLAND
{
@Override
public String toString(){ return "Bland"; }
},
ORDINARY
}


For demonstrating some of the primary characteristics of the Java enum , I will be using the following general Enum-handling methods (method names highlighted).


/**
* Print out the provided enum without explicitly calling its toString()
* method (which is implicitly called).
*
* @param theEnum The enum to be printed.
*/
private void outputEnumDirectly(final Enum theEnum)
{
System.out.println("Direct Enum: " + theEnum);
}

/**
* Print out the provided enum by explicitly calling its toString()
* method.
*
* @param theEnum The enum to be printed.
*/
private void outputEnumToString(final Enum theEnum)
{
System.out.println("\ttoString: " + theEnum.toString());
}

/**
* Print out the provided enum by explicitly calling its name() method
* (a final method provided by the parent Enum class).
*
* @param theEnum The enum to be printed.
*/
private void outputEnumName(final Enum theEnum)
{
System.out.println("\tname: " + theEnum.name() );
}

/**
* Print out the provided enum's ordinal value by explicitly calling its
* ordinal() method.
*
* @param theEnum The enum whose ordinal value is to be printed.
*/
private void outputEnumOrdinal(final Enum theEnum)
{
System.out.println("\tordinal: " + theEnum.ordinal());
}


Other commonly used enum-handling methods are shown in the next code listing.


private void processEnumForOutput(final Enum theEnum)
{
if ( theEnum == null )
{
return;
}
outputEnumDirectly(theEnum);
outputEnumToString(theEnum);
outputEnumName(theEnum);
outputEnumOrdinal(theEnum);
}

public static void printHeader(final String headerText)
{
System.out.println(
"------------------------------------------------------------------");
System.out.println("----- " + headerText);
System.out.println(
"------------------------------------------------------------------");
}


All of the methods shown above are generic enum-handling methods. The next code listing demonstrates a method written specifically to handle PlainOldEnum.


private PlainOldEnum getPlainEnumFromValue(final String enumValue)
{
PlainOldEnum plainEnum = null;
try
{
plainEnum = PlainOldEnum.valueOf(enumValue);
}
catch (IllegalArgumentException badValueForEnum)
{
System.err.println(
"ERROR: " + enumValue
+ " is not a valid value for enum PlainOldEnum:\n\t"
+ badValueForEnum.getMessage() );
}
return plainEnum;
}


This last code listing shows code that attempts to take a passed-in String and convert it to the appropriate enum with an underlying representation matching the provided String. It catches the unchecked exception IllegalArgumentException and prints a related warning out to the standard error.

When the PlainOldEnum is run through the general enum-handling methods shown above and through the specific getPlainEnumFromValue method, the results are as shown in the next screen snapshot.



The results depicted in the screen snapshot above tell us some things about the enum handling. First, we see that by overriding the toString method of PlainOldEnum.BLAND, we are able to have it printed implicitly and explicitly as the mixed-cased "Bland."

The second observation from the above snapshot that we see is the Enum.name() method returns "BLAND" despite the overridden toString() method that returns "Bland." This is not surprising considering that the Javadoc comments for this method state: "Returns the name of this enum constant, exactly as declared in its enum declaration." It is also interesting to note that one cannot override this method because it is declared as final in the Enum class.

A third observation, related to the second observation regarding the underlying representation of the enum value, is that the Enum.valueOf(String) method cannot return the appropriate Enum constant for "Bland" even though that is the String returned from the toString() for PlainOldEnum.BLAND. In other words, if one overrides the toString() method, it will change how the enum's value is presented, but it does not allow the valueOf to go the other way. This is the primary reason that I don't care for overriding an enum's String representation with toString(). I prefer to have my enums' toString() and valueOf() methods be symmetric. In other words, I like the String written out by the enum's toString() method to be the same one that can be used with the valueOf to get access to the appropriate enum value.

The issue observed above can also be seen with another example. The enum for this example, VehicleMakeEnum, is shown in the next code listing.

VehicleMakeEnum.java

public enum VehicleMakeEnum
{
CHEVROLET,
FORD,
HONDA,
PONTIAC,
SATURN,
TOYOTA;
}


The next code listing exercises VehicleMakeEnum and intentionally attempts to use its valueOf method incorrectly to demonstrate once again that the String value passed to valueOf must match the enum's underlying representation.


private VehicleMakeEnum getVehicleEnumFromValue(final String enumValue)
{
VehicleMakeEnum vehicleMake = null;
try
{
vehicleMake = VehicleMakeEnum.valueOf(enumValue);
}
catch (IllegalArgumentException badValueForEnum)
{
System.err.println(
"ERROR: " + enumValue
+ " is not a valid value for enum VehicleMakeEnum:\n\t"
+ badValueForEnum.getMessage() );
}
return vehicleMake;
}



printHeader("VehicleMakeEnum");
VehicleMakeEnum vehicleMake = VehicleMakeEnum.HONDA;
me.processEnumForOutput(vehicleMake);

vehicleMake = me.getVehicleEnumFromValue("CHEVROLET");
me.processEnumForOutput(vehicleMake);

vehicleMake = me.getVehicleEnumFromValue("Chevrolet");
me.processEnumForOutput(vehicleMake);

vehicleMake = me.getVehicleEnumFromValue("Saturn");
me.processEnumForOutput(vehicleMake);

vehicleMake = me.getVehicleEnumFromValue("TOYOTA");
me.processEnumForOutput(vehicleMake);


The output from running the above code is shown next.



This example again demonstrates that a mixed case String cannot be used with the enum's valueOf method to identify a specific enum value. This brings me to another useful feature of the Java enum. I don't like to override toString simply for a different representation because then it does not match the String required for valueOf to work properly. I prefer, therefore, to write a separate method for providing the enum value alternate representation. Another advantage of this approach is that I can present the same enum value in multiple ways.

An example of provide alternative representation methods for presenting an enum's value is best started with the StateEnum shown in the following code list.

StateEnum.java

public enum StateEnum
{
ALABAMA
{
@Override public String getAbbreviation() { return "AL"; }
@Override public String getCapital() { return "Montgomery"; }
@Override public int getStatehoodYear() { return 1819; }
@Override public String getSlogan() { return "Unforgettable"; }
@Override public String toDisplayString() { return "Alabama"; }
},
ALASKA
{
@Override public String getAbbreviation() { return "AK"; }
@Override public String getCapital() { return "Juneau"; }
@Override public int getStatehoodYear() { return 1959; }
@Override public String getSlogan() { return "North! To Alaska"; }
@Override public String toDisplayString() { return "Alaska"; }
},
ARIZONA
{
@Override public String getAbbreviation() { return "AZ"; }
@Override public String getCapital() { return "Phoenix"; }
@Override public int getStatehoodYear() { return 1912; }
@Override public String getSlogan() { return "Grand Canyon State"; }
@Override public String toDisplayString() { return "Arizona"; }
},
ARKANSAS
{
@Override public String getAbbreviation() { return "AR"; }
@Override public String getCapital() { return "Little Rock"; }
@Override public int getStatehoodYear() { return 1836; }
@Override public String getSlogan() { return "The Natural State"; }
@Override public String toDisplayString() { return "Arkansas"; }
@Override public String toString() { return "ARKANSAS"; }
},
CALIFORNIA
{
@Override public String getAbbreviation() { return "CA"; }
@Override public String getCapital() { return "Sacramento"; }
@Override public int getStatehoodYear() { return 1850; }
@Override public String getSlogan() { return "Find Yourself Here"; }
@Override public String toDisplayString() { return "California"; }
@Override public String toString() { return toDisplayString(); };
},
COLORADO
{
@Override public String getAbbreviation() { return "CO"; }
@Override public String getCapital() { return "Denver"; }
@Override public int getStatehoodYear() { return 1876; }
@Override public String getSlogan() { return "Colorful Colorado"; }
@Override public String toDisplayString() { return "Colorado"; }
};

abstract String getAbbreviation();
abstract String getCapital();
abstract int getStatehoodYear();
abstract String getSlogan();
abstract String toDisplayString();
}


As the code directly above shows, each value in the enum provides it own representation as a two-letter abbreviation (getAbbreviation()) and as a displayable String (toDisplayString()). For most of the states in the enum example above, I did not override toString, so the String returned by each toString will match the String needed in valueOf to get the appropriate enum value. However, I intentionally overrode CALIFORNIA.toString() for the example.

The next code listing shows enum-handling code specific to StateEnum.


private StateEnum getStateEnumFromValue(final String stateEnumValue)
{
StateEnum state = null;
try
{
state = StateEnum.valueOf(stateEnumValue);
}
catch (IllegalArgumentException badValueForEnum)
{
System.err.println(
"ERROR: " + stateEnumValue
+ " is not a valid value for enum StateEnum:\n\t"
+ badValueForEnum.getMessage() );
}
return state;
}

printHeader("StateEnum");
StateEnum state = StateEnum.ALASKA;
me.processEnumForOutput(state);

state = me.getStateEnumFromValue("Arizona");
me.processEnumForOutput(state);

state = me.getStateEnumFromValue("ARKANSAS");
me.processEnumForOutput(state);

state = me.getStateEnumFromValue("California");
me.processEnumForOutput(state);

state = me.getStateEnumFromValue("CALIFORNIA");
me.processEnumForOutput(state);

state = me.getStateEnumFromValue("COLORADO");
me.processEnumForOutput(state);


When the above StateEnum-handling code is executed, the output is that shown in the next screen snapshot.



We can see in the above output that "Arizona" cannot be used with valueOf even though its toDisplayString() method is overridden because the underlying representations of the states are all completely uppercase. The example with the California enum shows that even the specification of "California" in both toDisplayString() and toString does not allow the mixed-cased representation to be used with valueOf.

While the ability to represent the same enum value in different ways is a useful feature of Java enums, it is not the only useful benefit. The two methods in the following code listing show how much more efficient code that handles an enum can be if the enum in question has various support methods. In this example, StateEnum is used again. The first method "pretends" that useful methods for supplying the displayable name and for supplying the state capital are not present. Without those methods, one would need to switch on the enum value and then hard-code the response to it. The second method in the code listing shows how this same data (displayable string and capital) can be encapsulated within the enum and then easily rendered in the client code.


/**
* Process enums by switching on provided state and outputting hard-coded
* information dependent on the provided enum.
*
* @param state State on which to switch and act.
*/
public void processSimpleStateEnumsWithSwitch(final StateEnum state)
{
final String templateString = "The capital of SSSSS is CCCCC.";
switch ( state )
{
case ALASKA :
System.out.println(templateString.replace("SSSSS", "Alaska").replace("CCCCC", "Juneau"));
break;
case ARIZONA :
System.out.println(templateString.replace("SSSSS", "Arizona").replace("CCCCC", "Phoenix"));
break;
case ARKANSAS :
System.out.println(templateString.replace("SSSSS", "Arkansas").replace("CCCCC", "Little Rock"));
break;
case CALIFORNIA :
System.out.println(templateString.replace("SSSSS", "California").replace("CCCCC", "Sacramento"));
break;
case COLORADO :
System.out.println(templateString.replace("SSSSS", "Colorado").replace("CCCCC", "Denver"));
break;
default:
System.out.println( "WARNING: Apparently the state of " + state.name()
+ " was not considered in the processing code.");
break;
}
}

/**
* Process state enum. This is intended to show how much easier it is to
* process the StateEnum when the data is encapsulated in the StateEnum.
*
* @param state State to be processed with encapsulated data.
*/
public void processStatesWithEnumPower(final StateEnum state)
{
System.out.println( "The capital of " + state.toDisplayString() + " is "
+ state.getCapital() + "." );
}

printHeader("Compare switch to powerful enum");
me.processSimpleStateEnumsWithSwitch(StateEnum.ALABAMA);
me.processStatesWithEnumPower(StateEnum.ALABAMA);
me.processSimpleStateEnumsWithSwitch(StateEnum.ALASKA);
me.processStatesWithEnumPower(StateEnum.ALASKA);
me.processSimpleStateEnumsWithSwitch(StateEnum.ARIZONA);
me.processStatesWithEnumPower(StateEnum.ARIZONA);
me.processSimpleStateEnumsWithSwitch(StateEnum.ARKANSAS);
me.processStatesWithEnumPower(StateEnum.ARKANSAS);
me.processSimpleStateEnumsWithSwitch(StateEnum.CALIFORNIA);
me.processStatesWithEnumPower(StateEnum.CALIFORNIA);
me.processSimpleStateEnumsWithSwitch(StateEnum.COLORADO);
me.processStatesWithEnumPower(StateEnum.COLORADO);


The last code listing shows how much cleaner and simpler it is for the client code when the enum encapsulates its static data. Another advantage, as discussed in A Better Way to Use Java Enum than Switch, is that no concern about missing a case statement in the switch is present with the cleaner, simpler encapsulated enum approach. In the above example, I intentionally neglected to place a case statement for ALABAMA to show how and why the default keyword is necessary.

The output for running this code is shown next.



As this output demonstrates, encapsulating data in the enum allows for the same functionality to be performed by the client, but the client's code is much cleaner and safer. One thing related to this that I did not demonstrate here is that one can even pass the information associated with an enum to it via a constructor. This can be preferable to providing the information in the individual methods on each enum value. For example, I now show a piece of the StateEnum (Alabama's and Arkansas's entries only) demonstrating this approach.

StateWithConstructorEnum.java

public enum StateWithConstructorEnum
{
ALABAMA("Alabama", "AL", "Montgomery", "Unforgettable", 1819),
ALASKA("Alaska", "AK", "Juneau", "North! To Alaska", 1959),
ARIZONA("Arizona", "AZ", "Phoenix", "Grand Canyon State", 1912),
ARKANSAS("Arkansas", "AR", "Little Rock", "The Natural State", 1836),
CALIFORNIA("California", "CA", "Sacramento", "Find Yourself Here", 1850),
COLORADO("Colorado", "CO", "Denver", "Colorful Colorado", 1876);

private String displayName;
private String abbreviation;
private String capital;
private String slogan;
private int statehoodYear;

StateWithConstructorEnum(
final String displayName,
final String abbreviation,
final String capital,
final String slogan,
final int statehoodYear)
{
this.displayName = displayName;
this.abbreviation = abbreviation;
this.capital = capital;
this.slogan = slogan;
this.statehoodYear = statehoodYear;
};

public String getAbbreviation() { return this.abbreviation; }
public String getCapital() { return this.capital; }
public int getStatehoodYear() {return this.statehoodYear; }
public String getSlogan() { return this.slogan; }
public String toDisplayString() { return this.displayName; }
}


The approach shown immediately above can often be preferable because all of the data encapsulated with each enum value is easily identifiable in the constructor of that enum value and then single public methods for the entire enum can be defined rather than overriding these methods for each individual value in the enum. Another advantage of this approach occurs in situations when multiple methods use the same underlying data, which only needs to be expressed once in the constructor rather than each time in every output method it affects.

Java enums are very powerful, but there are obviously times when a regular class is preferable to the enum. Enums are fits for finite sets of data and are best used with static data. The StateEnum was a perfect example of this. All of the data returned by the methods encapsulated in that enum are for static data. Although more dynamic methods can be used with enums, I tend to prefer to place dynamic behavior in a class rather than an enum, even if it is in a class that "wraps" a member enum. The article Java Enums Want to Be Classes - Or Do They? provides good coverage of the issue of using too powerful of enums. The blog entry Java Practice - When Not To Use Enums (and its feedback comments) provides useful information on when not to use enum.