Liferay Mobile Support

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Wednesday, 11 April 2007

Fun with Java Enums

Posted on 06:50 by Unknown

Way back in Java 1.5, enum types were added to the Java spec. The idea is simple enough; create an object with a fixed set of valid values. The values are constant, like coins. Coins come in a fixed number of types (penny, nickel, dime, etc) and each type has a fixed value (1, 5, 10, ... ). An enum type allows you to do just that in your code:

public class Coins {
enum Coin {
PENNY(1),NICKEL(5),DIME(10),QUARTER(25);
int value;
Coin( int v ) { value = v; }
}

public static void main(String[] args) {
System.out.println("A penny is worth: " + Coin.PENNY.value);
}
}


A Coin enum type is declared and each possible type of Coin is given it's respective value. And the code prints just as you would expect:

A penny is worth: 1


Part of the assumption is that a penny is always a penny and always worth 1 cent. However, if we add the following lines of code to the main method, let's see what happens.

Coin.PENNY.value = 1000;
System.out.println("A penny is now worth: " + Coin.PENNY.value);


When the code is compiled and run again, what is the output? In case you were wondering, it does compile quite nicely.

A penny is worth: 1
A penny is now worth: 1000


Now that's the way all my investments should grow! Seriously, though, what is the problem? The problem is that the value, and any instance variables in an enum, are not magically immutable. The enum type does not do any special checking to ensure that the instances of the type (PENNY, NICKEL, ...) remain constant. Under the covers, the enum type is converted to a static class with static members for each
of the declared possbile values like this:

static final class Coins$Coin extends Enum
{
public static final Coins$Coin[] values()
{
return (Coins$Coin[])$VALUES.clone();
}

public static Coins$Coin valueOf(String s)
{
return (Coins$Coin)Enum.valueOf(Coins$Coin, s);
}

public static final Coins$Coin PENNY;
public static final Coins$Coin NICKEL;
public static final Coins$Coin DIME;
public static final Coins$Coin QUARTER;
int value;
private static final Coins$Coin $VALUES[];

static
{
PENNY = new Coins$Coin("PENNY", 0, 1);
NICKEL = new Coins$Coin("NICKEL", 1, 5);
DIME = new Coins$Coin("DIME", 2, 10);
QUARTER = new Coins$Coin("QUARTER", 3, 25);
$VALUES = (new Coins$Coin[] {
PENNY, NICKEL, DIME, QUARTER
});
}

private Coins$Coin(String s, int i, int j)
{
super(s, i);
value = j;
}
}


Our value is given the same access modifiers in the generated class as it was given when we defined the enum. Meaning that the value is not able to be modified by any member of the same package.

The fix



The fix is fairly simple. Make the value instance variable final:

final int value;


Now when the code that tries to modify the value is compiled, this error:

Coins.java:28: cannot assign a value to final variable value
Coin.PENNY.value = 1000;
^
1 error


Problem solved. Right? Well, not so fast. For primitive types, yes. But for descendants of Object, maybe not. What if instead of an int, value was something like a Map. You could then do Coin.PENNY.value.put("bad key", "bad value") and the compiler would be perfectly happy with it.

To fix the problem, ensure that the Map is unmodifiable or immutable

public class Coins
{
enum Coin {
PENNY(1),NICKEL(5),DIME(10),QUARTER(25);

final Map value;

Coin( int v ) {
Map newValue = new HashMap();
newValue.put( "cents", v );
value = Collections.unmodifiableMap( newValue );
}
}

public static void main(String[] args) {
System.out.println("A penny is worth: " +
Coin.PENNY.value.get("cents"));
}
}


Summary



While the compiler will ensure that the enum types are immutable, it is the responsibility of the developer to ensure that any instance variables added to the enum are also immutable. This means the instance variable needs to be final AND the type of the instance variable must itself be immutable.
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Posted in | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • ASP.NET caching based on a cookie
    You have to use VaryByCustom parameter. Your OutputCache directive will look like this and you have declare the following method in which w...
  • Chapter�16.�Portlet MVC Framework
    Spring Portlet MVC applies the same principles to portlet development as the the Spring Web MVC framework applies to servlet development. F...
  • Wicket and Guice
    Are you sick of XML? I sure am. While I really like Spring Framework, I am sick of all the XML. Writing unit tests is hard enough, but ho...
  • Open Source Technical Support by OpenLogic
    This gets filed under the category of "Why didn't I think of this?". What an excellent business model. Take a free product a...
  • Linux.com | GNU Emacs 22 finally released
    I have just recently switched from Emacs to Eclipse for my Java development work. I still use Emacs almost everyday I even have an Emacs r...
  • Clojure: lazy seq + database = bad
    In my work on topoged-hibernate I naively thought that it would be great to return a lazy-seq of the results of a query like: However, th...
  • Hexlify in Clojure
    Looking at this gist , I have created functionality similar to EMACS hexlify-buffer. In EMACS, it reads a binary file and presents two views...
  • Watch "Advanced Topics in Programming Languages: Java Puzzlers, Episode VI"
    Advanced Topics in Programming Languages: Java Puzzlers, Episode VI 1 hr 13 min 49 sec - Jul 23, 2007 Average rating: (23 ratings) Descr...
  • LISP Cycles
    I admit it, I like LISP. There are a certain set of programming problems that it handles elegantly. I feel the same about AWK, BASH, SQL a...
  • Coding Horror: The "Works on My Machine" Certification Program
    I think we will be doing this at work. Coding Horror: The "Works on My Machine" Certification Program : " 1. Compile your a...

Categories

  • 1.3.0
  • abiword
  • apache
  • archiva
  • browser
  • clojure
  • ClojureScript
  • derby
  • exception
  • java
  • javaone
  • javascript
  • jdk
  • jquery
  • lein
  • Liferay
  • page background
  • patterns
  • swank
  • watermrk

Blog Archive

  • ►  2013 (3)
    • ►  November (1)
    • ►  July (1)
    • ►  May (1)
  • ►  2012 (5)
    • ►  December (3)
    • ►  February (1)
    • ►  January (1)
  • ►  2011 (5)
    • ►  October (1)
    • ►  September (1)
    • ►  August (1)
    • ►  February (1)
    • ►  January (1)
  • ►  2010 (6)
    • ►  September (6)
  • ►  2009 (10)
    • ►  July (2)
    • ►  June (1)
    • ►  April (5)
    • ►  March (1)
    • ►  January (1)
  • ►  2008 (23)
    • ►  December (1)
    • ►  November (1)
    • ►  October (1)
    • ►  August (1)
    • ►  July (2)
    • ►  June (3)
    • ►  May (6)
    • ►  April (4)
    • ►  March (2)
    • ►  February (1)
    • ►  January (1)
  • ▼  2007 (45)
    • ►  December (7)
    • ►  October (5)
    • ►  September (1)
    • ►  August (4)
    • ►  June (3)
    • ►  May (15)
    • ▼  April (7)
      • Wicket and Guice
      • Felipe Gaucho's Blog: The name is One, JavaONE !
      • Matthew Smith: JDK Community Star
      • Communciating between JSR-168 portlets and the por...
      • Fun with Java Enums
      • Java One 2007
      • Elusive unit test error
    • ►  March (3)
Powered by Blogger.

About Me

Unknown
View my complete profile