0

I have some enums like this:

public enum Classification {
    UNKNOWN("Unknown"),
    DELETION("Deletion"),
    DUPLICATION("Duplication"), ....

but some of them have like 20 members, so currently in code I deal with them with huge if/else blocks like this:

int classification= rs.getInt("classification");
        if (classification == Classification.UNKNOWN.ordinal()) {
            variant.setClassification(Classification.UNKNOWN);
        } else if (classification == Classification.DELETION.ordinal()) {
            variant.setClassification(Classification.DELETION);

( rs is from JDBC tho).

Does Java have a better way this these big if/else blocks to do what I am doing? some sorting of looping through it?

Bohn
  • 26,091
  • 61
  • 167
  • 254
  • 2
    aah, i get it. so you want to store values representing enum values in a database? Look [here](http://stackoverflow.com/questions/229856/ways-to-save-enums-in-database) – flying sheep Aug 25 '11 at 16:12
  • see also http://stackoverflow.com/questions/1080904/how-can-i-lookup-a-java-enum-from-its-string-value/1080914 – Gareth Davis Aug 25 '11 at 16:17

8 Answers8

10

You could use Enum#values() to get all enum values in an array. The ordinal maps 1:1 to the array index. Add the following method fo your Classification enum:

public static Classification of(int ordinal) {
    if (0 <= ordinal && ordinal < values().length) {
        return values()[ordinal];
    }
    throw new IllegalArgumentException("Invalid ordinal " + ordinal);
}

and use it as follows

Classification classification = Classification.of(rs.getInt("classification"));
// ...

However, using enum's ordinal for this is not the best practice. What if some developer rearranges the enum's values or adds/removes values? Even the javadoc warns that it has usually no use for developers. Rather give each enum value a fixed identifier. You could pass it in as an additional argument of the enum constructor argument. You could even use enum's String representation for that.

UNKNOWN(1, "Unknown"),
DELETION(2, "Deletion"),
DUPLICATION(3, "Duplication"),
// ...

Then use that value for DB instead and modify the of() method to walk through them in a foreach loop:

public static Classification of(int id) {
    for (Classification classification : values()) {
        if (classification.id == id) {
            return classification;
        }
    }
    throw new IllegalArgumentException("Invalid id " + id);
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I don’t get it. enums *are* fixed identifiers, that’s their whole point. The mysterious rs instance should have a method `.getClassification`, which returns the fitting enumeration value right away. – flying sheep Aug 25 '11 at 16:09
  • 1
    @flying: it's the `ResultSet` from JDBC. – BalusC Aug 25 '11 at 16:11
  • rs is a resultset object (i assume). – Oh Chin Boon Aug 25 '11 at 16:11
  • thanks, now i see. wrong question then, he should have looked [here](http://stackoverflow.com/questions/229856/ways-to-save-enums-in-database) instead. – flying sheep Aug 25 '11 at 16:13
  • Can't that loop just be a array index lookup? values() on enums is defined such that it returns the enum instances in the order they are defined and ordinal() is defined as the position of an Enum in the order that they are defined – Gareth Davis Aug 25 '11 at 16:16
  • @Gareth: look at the answer to the question i linked to; BalusC also mentioned it: the ordinal is not safe, as enum values can should be able to be rearranged freely. – flying sheep Aug 25 '11 at 16:18
  • 1
    @Gareth: you're right that the ordinal maps 1:1 to the enum value index. Just using `Classification.values()[ordinal]` would be better than looping over it. – BalusC Aug 25 '11 at 16:28
  • @flying sheep, agreed..but since the first solution is using ordinal then it perhaps should be as correct as can be – Gareth Davis Aug 25 '11 at 16:29
  • but `name` and `valueOf` are made to be counterparts of each other: `Classification.UNKNOWN == Classification.valueOf("UNKNOWN") && Classification.UNKNOWN.name() == "UNKNOWN"` – flying sheep Aug 25 '11 at 16:42
3

If the db value is the ordinal of the Enum then:

int classification= rs.getInt("classification");
variant.setClassification(Classification.values()[classification]);

I'll leave bounds checking as an exercise for the reader.

Gareth Davis
  • 27,701
  • 12
  • 73
  • 106
1

You can loop through an enumeration’s values via the object the someEnum.values() method returns:

for (Classification clz : Classification.values()) doSomethingWith(clz);

found here

I don’t know how exactly I can help you, since i don’t know what rs.getInt(String) does.

It seems to give back an Integer representing a enum value of Classification, but why?

flying sheep
  • 8,475
  • 5
  • 56
  • 73
1

Use variant.setClassification(YourEnumClassHere.values()[classification]). Enum.values() returns an array of all the declared enums in that class.

Jeffrey
  • 44,417
  • 8
  • 90
  • 141
1

Instead of storing ordinal, you can store the name and use the valueOf method to convert the String back to your Enum type.

Brigham
  • 14,395
  • 3
  • 38
  • 48
1

If you willing and able to store a string representation (this is a good technique) of the ENUM in your database, see Reference from Gareth Davis in comments above. If you are unwilling and/or unable to store a string representation and must continue with an ordinal representation, I suggest that a Map is called for. Here is some example code:

public class EnumMap
{
    private enum FistSounds
    {
        Blam, Kapow, Zowie, Biff;

        private static Map<Integer, FistSounds> ordinalMap = new HashMap<Integer, FistSounds>();

        static
        {
            ordinalMap.put(Blam.ordinal(), Blam);
            ordinalMap.put(Kapow.ordinal(), Kapow);
            ordinalMap.put(Zowie.ordinal(), Zowie);
            ordinalMap.put(Biff.ordinal(), Biff);
        }

        public static final FistSounds getByOrdinal(final int enumIndex)
        {
            return ordinalMap.get(enumIndex);
        }
    }

    public static void main(String[] args)
    {
        FistSounds fistSound;

        for (int index = -1; index < 5; ++index)
        {
            fistSound = FistSounds.getByOrdinal(index);

            System.out.print("Ordinal: ");
            System.out.print(index);
            System.out.print(", FistSound: ");
            System.out.println(fistSound);
        }
    }
}
Community
  • 1
  • 1
DwB
  • 37,124
  • 11
  • 56
  • 82
0

I'd recommend using a switch statement, if the logic to execute is different for each case....

do as @Gareth Davis instructs and then just have a switch statement and handle each case as required.

Peter Perháč
  • 20,434
  • 21
  • 120
  • 152
0

Enums are also eligible to be used in switch statements see here

thejartender
  • 9,339
  • 6
  • 34
  • 51