0

In the database I'm using this with there are magic numbers which I want to map to the State enum, and vice-versa. I'm intrigued by the static declaration of undefined.code = 0. What does this declaration, if that's what it is, actually do?

package net.bounceme.dur.data;

public enum State {

    undefined(0), x(1), o(2), c(3), a(4), l(5), d(6);
    private int code = 0;

    static {
        undefined.code = 0;
        x.code = 1;
        o.code = 2;
        c.code = 3;
        a.code = 4;
        l.code = 5;
        d.code = 6;
    }

    State(int code) {
        this.code = code;
    }

    public int getCode() {
        return this.code;
    }

    public static State getState(int code) {
        for (State state : State.values()) {
            if (state.getCode() == code) {
                return state;
            }
        }
        return undefined;
    }

}

Currently, the usage for this enum factory method is as so:

  title.setState(State.getState(resultSet.getInt(5)));

but I would be interested in any and all alternatives.

Makoto
  • 104,088
  • 27
  • 192
  • 230
Thufir
  • 8,216
  • 28
  • 125
  • 273
  • 2
    Why would you do this? Just change `private int code = 0;` to `private final int code;` and assign it once. What is the point of the `static` block? – Elliott Frisch Jul 07 '14 at 07:17
  • It might help to think of `enum`s as regular objects with a guaranteed singleton property. So `code` is just a field for a `State` object, and `undefined.code` is accessing that field for a particular instance of a `State` object. – awksp Jul 07 '14 at 07:17
  • @ElliottFrisch I don't know what the point of the static block is, that's part of what I'm asking. It's used in a similar question to mine, and appears to...assign values? – Thufir Jul 07 '14 at 07:18
  • 2
    The static block doesn't serve any purpose. It does what the constructor already does. – JB Nizet Jul 07 '14 at 07:20

4 Answers4

4

I've removed the useless static block and improved the inverse function.

public enum State {

private static Map<Integer,State> int2state = new HashMap<>();

undefined(0), x(1), o(2), c(3), a(4), l(5), d(6);
private int code;

State(int code) {   // executed for *each* enum constant
    this.code = code;
    int2state.put( code, this ); 
}

public int getCode() {
    return this.code;
}

public static State getState(int code) {
    return int2state.get(code);
}
}

If the "code" integers are definitely ordinals from 0 up, you can omit the Constructor parameter, private int code and map like so:

int2state.put( this.ordinal(), this );
laune
  • 31,114
  • 3
  • 29
  • 42
  • how is the map populated? I will have to print it out to see, but it **seems** to me that only a **single** entry is made into the map. How does it have **all** the mapping entries? – Thufir Jul 07 '14 at 07:37
  • 1
    see my second edit - comment on the constructor. This one is executed once for each enum value. – laune Jul 07 '14 at 07:39
  • 2
    The constructor is called multiple times, once per enum instance. So the map is fully populated. You should accept this answer Thufir, it's correct and efficient. – vikingsteve Jul 07 '14 at 07:41
2

In the code you posted, the static block line

undefined.code = 0;

It accesses the enumerated constant undefined, and blindly sets the value of the mutable field code from 0 to 0. Basically, the constant was defined here

undefined(0)

with a code of 0. Likewise with x and 1. And so on.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
2

Well it really does the same thing as the constructor - sets the code associated each enum value.

In your example, the static { ... } block is superfluous (unnecessary) and should probably be removed since it duplicates the line starting with underfined(0).

The point where Enum usage gets tricky is with the lookup (in your case, getState(...) method). The case statement here really duplicates the code a third time, and you might be better to build a Map that takes a code (int) and returns the enum (State) - just google around, there are plenty of examples on how to do this.

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
2

Just a hint. It is much more readable to change your getState(int) method to

    public static State getState(int code) {
        for (State state : State.values()) {
            if (state.getCode() == code) {
                return state;
            }
        }
        return undefined; 
    }
Floris
  • 1,082
  • 10
  • 26