Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to implement `next` and `previous` on an enum type?

Suppose I have an enum:

enum E {     A, B, C; } 

As shown in this answer by lucasmo, enum values are stored in a static array in the order that they are initialized, and you can later retrieve (a clone of) this array with E.values().

Now suppose I want to implement E#getNext and E#getPrevious such that all of the following expressions evaluate to true:

E.A.getNext() == E.B E.B.getNext() == E.C E.C.getNext() == E.A  E.A.getPrevious() == E.C E.B.getPrevious() == E.A E.C.getPrevious() == E.B 

My current implementation for getNext is the following:

public E getNext() {     E[] e = E.values();     int i = 0;     for (; e[i] != this; i++)         ;     i++;     i %= e.length;     return e[i]; } 

and a similar method for getPrevious.

However, this code seems cumbersome at best (e.g., "empty" for loop, arguable abuse of a counter variable, and potentially erroneous at worst (thinking reflection, possibly).

What would be the best way to implement getNext and getPrevious methods for enum types in Java 7?


NOTE: I do not intend this question to be subjective. My request for the "best" implementation is shorthand for asking for the implementation that is the fastest, cleanest, and most maintainable.

like image 696
wchargin Avatar asked Jun 09 '13 03:06

wchargin


People also ask

Can you increment an enum in Java?

You can't "increment" an enum, but you can get the next enum: // MyEnum e; MyEnum next = MyEnum.

How do you use enums correctly?

You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values. Examples would be things like type constants (contract status: “permanent”, “temp”, “apprentice”), or flags (“execute now”, “defer execution”).

How is enum implemented?

Enums are statically created when the enum class is first loaded and are immutable. You must have a constructor in the enum class if you want to assign different values to your enum. After the constructor was finished you cannot change the enums value (immutable as said).

What is enum most useful in creating?

Enums are used to create our own data type like classes. The enum data type (also known as Enumerated Data Type) is used to define an enum in Java. Unlike C/C++, enum in Java is more powerful. Here, we can define an enum either inside the class or outside the class.

What is an enum in Java?

Overview In this tutorial, we'll learn what Java enums are, what problems they solve, and how some of their design patterns can be used in practice. Java 5 first introduced the enum keyword. It denotes a special type of class that always extends the java.lang.Enum class.

How to access enum items in a list?

You can access enum items with the dot syntax: Level myVar = Level.Medium; Console.WriteLine(myVar); Try it Yourself » Enum is short for "enumerations", which means "specifically listed".

What is enenum in Java?

Enum is short for "enumerations", which means "specifically listed". By default, the first item of an enum has the value 0. The second has the value 1, and so on. To get the integer value from an item, you must explicitly convert the item to an int:

How do I get the integer value from an enum?

By default, the first item of an enum has the value 0. The second has the value 1, and so on. To get the integer value from an item, you must explicitly convert the item to an int: You can also assign your own enum values, and the next items will update the number accordingly:


2 Answers

Try this:

public static enum A {      X, Y, Z;     private static A[] vals = values();     public A next()     {         return vals[(this.ordinal()+1) % vals.length];     } 

Implementation of previous() is left as an exercise, but recall that in Java, the modulo a % b can return a negative number.

EDIT: As suggested, make a private static copy of the values() array to avoid array copying each time next() or previous() is called.

like image 116
Jim Garrison Avatar answered Oct 15 '22 12:10

Jim Garrison


Alternatively, one can go somehow along the lines of the following idea:

public enum SomeEnum {   A, B, C;    public Optional<SomeEnum> next() {     switch (this) {       case A: return Optional.of(B);       case B: return Optional.of(C);       // any other case can NOT be mapped!       default: return Optional.empty();   } } 

Notes:

  1. In contrast to the other answer, this way does some implicit mapping; instead of relying on ordinal(). Of course that means more code; but it also forces the author to consider what it means to add new constants or remove existing ones. When relying on ordinal, your implicit assumption is that the order is based on the order used for the enum constant declaration. So when somebody comes back 6 months later and has to add a new constant, he has to understand that the new constant Y needs X, Y, Z ... instead of just appending X, Z, Y!
  2. There might be situations where it doesn't make any sense for the "last" enum constant to have the "first" as successor. Think of T-Shirt sizes for examples. XXL.next() is for sure not XS. For such situations, using Optional is the more appropriate answer.
like image 26
GhostCat Avatar answered Oct 15 '22 12:10

GhostCat