Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java enum auto-increment entries?

Tags:

java

enums

Does Java allow something like good ol' C or even C# in the sense that you can define an enum with fields that grow in value automatically, and start at an optionally given value?

E.g.

In C or C#:

enum Foo { A = 10, B, C, D = 5000, E, Fish };

Yields A = 10, B = 11, C = 12, D = 5000, E = 5001, Fish = 5002.

like image 584
Alex Budovski Avatar asked Jan 13 '10 08:01

Alex Budovski


2 Answers

In Java you can't specify the ordinal values explicitly at all. They always autoincrement, from 0, with no control over it.

If you want other custom values, you need to put them in constructor calls and store them yourself. You can get autoincrement, but it's icky as heck:

import java.util.EnumSet;

// Please don't ever use this code. It's here so you can point and laugh.
enum Foo 
{ 
    A(10), B, C, D(5000), E, Fish;

    private static int nextValue;
    private int value;

    private Foo()
    {
        this(Counter.nextValue);
    }

    private Foo(int value)
    {
        this.value = value;
        Counter.nextValue = value + 1;
    }

    public int getValue() 
    {
        return value;
    }

    private static class Counter
    {
        private static int nextValue = 0;
    }
}

public class Test
{
    public static void main(String[] args)
    {
        for (Foo foo : EnumSet.allOf(Foo.class))
        {
            System.out.println(foo.name() + " " + 
                               foo.ordinal() + " " + 
                               foo.getValue());
        }
    }
}

Note the need for the nested class, because you can't access static fields within an enum constructor. Ick, ick, ick. Please don't do this.

like image 165
Jon Skeet Avatar answered Nov 01 '22 15:11

Jon Skeet


This is a design choice of Java Enums to not support to change the ordinal values. Basically, they are not stable enough to depend on them. If you change the position of B and C in your example clients depending on the ordinal values are broken. This may happen unintentionally.

The problem is described in Effective Java Item 31: Use instance field instead of ordinals.

You can emulate the behavior in a stable manner:

enum X{
    A(10), B(A), C(B), D(5000), E(D), F(E);

    private final int value;

    X(int value){
        this.value = value;
    }

    X(X preceding){
        this.value = preceding.getValue() + 1;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.name() + "(" + this.value + ")";
    }

    static {
        Set<Integer> values = new HashSet<Integer>();
        for(X x : X.values()) values.add(x.value);
        assert(values.size() == X.values().length); //no duplicates
    }
}

With this definition you may change the order of the values without breaking clients.

Calling for(X x : X.values()) System.out.println(x); returns:

A(10)
B(11)
C(12)
D(5000)
E(5001)
F(5002)
like image 37
Thomas Jung Avatar answered Nov 01 '22 13:11

Thomas Jung