27

Is it possible to implement the ++ operator for an enum?

I handle the current state of a state machine with an enum and it would be nice to be able to use the ++ operator.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
TomBoo
  • 391
  • 1
  • 4
  • 11
  • If you are talking about operator overloading, no, this can't be done with Java – BackSlash Jul 15 '13 at 21:41
  • 6
    Please see [this answer](http://stackoverflow.com/a/17006263/18157). Note that ++ cannot have a direct counterpart for enums because an enum constant is immutable. The best you can do is define a `next()` method that returns the next enum value. – Jim Garrison Jul 15 '13 at 21:45
  • 4
    This is a misleading comparison: integer constants are immutable too (in that `++` doesn't change what `5` means), but `++` works fine because it changes *which* integer your local "refers to". `++` on enums could do the same thing, by changing the local `season` to point at `SUMMER` instead of `SPRING`. – amalloy Jul 15 '13 at 22:41

2 Answers2

60

You can't "increment" an enum, but you can get the next enum:

// MyEnum e;
MyEnum next = MyEnum.values()[e.ordinal() + 1];

But better would be to create an instance method on your enum.

Note well how the problematic next value is handled for the last enum instance, for which there is no "next" instance:

public enum MyEnum {

    Alpha,
    Bravo,
    Charlie {
        @Override
        public MyEnum next() {
            return null; // see below for options for this line
        };
    };

    public MyEnum next() {
        // No bounds checking required here, because the last instance overrides
        return values()[ordinal() + 1];
    }
}

So you could do this:

// MyEnum e;
e = e.next();

The reasonable choices you have for the implementation of the overidden next() method include:

  • return null; // there is no "next"
  • return this; // capped at the last instance
  • return values()[0]; // rollover to the first
  • throw new RuntimeException(); // or a subclass like NoSuchElementException

Overriding the method avoids the potential cost of generating the values() array to check its length. For example, an implementation for next() where the last instance doesn't override it might be:

public MyEnum next() {
    if (ordinal() == values().length - 1)
        throw new NoSuchElementException();
    return values()[ordinal() + 1];
}

Here, both ordinal() and values() are (usually) called twice, which will cost more to execute than the overridden version above.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 2
    You don't really need that `MyEnum` parameter in the `next`-method, do you? – Michael Lang Jul 15 '13 at 21:59
  • 2
    @MichaelLang damn - I started out with a static method then changed it to an instance method, but left the parameter in :( Thx. – Bohemian Jul 15 '13 at 22:00
  • 1
    Jim Garrison's answer (see his link above) calls values() only once -- each call copies the array. Also, it handles incrementing past the end of the enumeration, with the modulus operator. – Andy Thomas Jul 15 '13 at 22:13
  • 1
    @AndyThomas Copying the array is an optimization. Cluttering the code with such "performance improvements" will almost certainly not make a *measurable* difference. Unless the code is used in a tight loop and the `values()` method is proven to be an issue, it's better to leave the code cleaner. – Bohemian Jul 15 '13 at 22:20
  • 1
    @AndyThomas I had a brainwave. See edited answer for non-copy, but single call to `values()` implementation, that also is IMHO an example of good OO code. – Bohemian Jul 16 '13 at 11:10
  • @TomBoo Thanks for the accept. I have since typed in a better solution - please read it. Cheers. – Bohemian Jul 16 '13 at 11:17
  • 2
    Overriding in the last enum is a cool idea to avoid a conditional, and to call values() only once per call. Going to remember that pattern. I'm aware of the negatives of premature optimization. But for a public enum that might be used in ways that I don't expect, adding a single field declaration seems worth it to me. – Andy Thomas Jul 16 '13 at 12:40
  • Do you mean to add .length to values()? public MyEnum next() { if (ordinal() > values().length - 1) throw new NoSuchMethodException(); return values()[ordinal() + 1]; } – Peter Jan 06 '15 at 18:04
  • 2
    @peter yes - thanks for letting me know. Actually the code required a little more repair than just that, which I've put in place. – Bohemian Jan 06 '15 at 22:32
4

No. Java does not support customized operator overloading for any user-defined type, including enums.

However, you could define a method in the enum class that returned the next enumerator.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151