Polymorphic Enums in J2SE 5.0

by Jeff Langr

February 12, 2004

Java version 5.0 introduces many dramatic new language features. This article further discusses the new enum facility, demonstrating how you can define enum constants polymorphically. You may want to first read the article Typesafe Enum: Using enum in J2SE 5.0.

The Grade enum

In my first article on enum, I introduced a Grade enum. Here is the code:

    enum Grade {
       A("great"),
       B("good"),
       C("ok"),
       D("eh"),
       F("loser");
    
       private String message;
    
       Grade(String message) {
          this.message = message;
       }
    
       String getMessage() {
          return message;
       }
    }

Suppose you want the ability to determine whether a test score falls into a specific grade. A score of 90 up through 100 is an A; an 80 up to but not including 90 is a B, and so on. A score of less than (but not including) 60 warrants an F.

You can modify the Grade enum to take a lower and upper range for each grade. You can then provide a method (includes) to determine whether or not a score maps to the current Grade enum:

    public enum Grade {
       A("great", 90.0, 100.0),
       B("good", 80.0, 90.0),
       C("ok", 70.0, 80.0),
       D("eh", 60.0, 70.0),
       F("loser", 0.0, 60.0);
    
       private String message;
       private double from;
       private double to;
    
       Grade(String message, double from, double to) {
          this.message = message;
          this.from = from;
          this.to = to;
       }
    
       String getMessage() {
          return message;
       }
    
       boolean includes(double score) {
          return from <= score && score < to;
       }
    }

So far, nothing new. The only problem is that it won't work. The to value represents the top end of the grade range and must be exclusive–except for an A. A perfect score of 100 must report back as an A, but it does not with the above code.

One solution would be to include special logic in the definition of enum, or perhaps modify the constructor to take a boolean representing whether or not the range upper bound is inclusive.

Another solution is to have the declaration of the Grade.A enum constant override the definition for includes.

    public enum Grade {
       A("great", 90.0, 100.0) {
          boolean includes(double score) {
             return super.includes(score) || score == to;
          }
       },
       B("good", 80.0, 90.0),
       C("ok", 70.0, 80.0),
       D("eh", 60.0, 70.0),
       F("loser", 0.0, 60.0);
    
       private String message;
       private double from;
       protected double to;
    
       Grade(String message, double from, double to) {
          this.message = message;
          this.from = from;
          this.to = to;
       }
    
       String getMessage() {
          return message;
       }
    
       boolean includes(double score) {
          return from <= score && score < to;
       }
    }

You supply the new definition for includes inline, just as if you were overriding a method in an inner class declaration.

Note that you must also define the to variable as protected in order for this to work.

If you want a different implementation for an enum method for each and every enum constant, you can declare both the method and the enum type as abstract.

Comments

Pingback: Langr Software Solutions » Typesafe Enum: Using enum in J2SE 5.0

Share your comment

Jeff Langr

About the Author

Jeff Langr has been building software for 40 years and writing about it heavily for 20. You can find out more about Jeff, learn from the many helpful articles and books he's written, or read one of his 1000+ combined blog (including Agile in a Flash) and public posts.