简体   繁体   中英

How do I return a list of enum elements for a generic enum?

I am making a card game with a friend and I decided to make a card viewer, we input the all of card details into a text document and my program reads each card in, line by line.

Different types of card have different properties, all properties are represented in some type of enum.

I have some code which converts lists of strings into lists of enum properties. Example Enums:

public enum Race{
ELVES, HUMANS, DWARFS
} 

public enum Rarity{
COMMON, UNCOMMON, RARE
}

Assuming a card can have multiple Races and multiple rarities I want to make a method that can take a list of strings and a type of enum and return a list of enum values, eg

// Take in an array of strings and a type of Enum value to convert them to
public <Type extends Enum<Type>> Type[] getValues(String[] strings){

// Make an array to hold the enum values
Type[] values = new Type[strings.length];

// For each string, convert it into an enum value and add it to the array
for (int i = 0; i < strings.lenght; i++)
    values[i] = Type.valueOf(strings[i]);

return values;
}

I know this method doesn't work, but I hope it portrays at least what I am trying to do, I'd like a method to which I can send any list of strings and it will convert them into a list of EnumValues, eg convert the strings {"ELVES", HUMANS"} to the relevant Race values {ELVES, HUMANS}.

You might ask why I don't just make separate methods like

convertRaceStings(String[] strings){//method workings here}
convertRarityStings(String[] strings){//method workings here}

unfortunately the two enums used here are simple examples, there are a lot more enums which would each require another method.

You should use an EnumSet instead of an array of enums. It is more memory efficient. As a bonus you won't have to mess with generics arrays.

Your method will then look like:

private static <T extends Enum<T>> EnumSet<T> createEnumSet(Class<T> clazz, String... values) {
    EnumSet<T> set = EnumSet.noneOf(clazz);
    for(String value : values) {
        set.add(Enum.valueOf(clazz, value));
    }
    return set;
}

Well except if you need to have multiple instance of the same enum.

Usage:

final EnumSet<Race> races = createEnumSet(Race.class, "HUMANS", "DWARFS");

It would be easier if you passed the enum type as well - that would enable you to use the Enum#valueOf static method :

public static void main(String[] args) {
    System.out.println(get("ELVES", Race.class));
    System.out.println(get("COMMON", Rarity.class));
}

public static <T extends Enum<T>> T get(String value, Class<T> clazz) {
    return Enum.valueOf(clazz, value);
}

public static enum Race {

    ELVES, HUMANS, DWARFS
}

public static enum Rarity {

    COMMON, UNCOMMON, RARE
}

If you don't want to pass the enum class as a second argument, you will need to maintain a mapping somewhere.

Working with arrays is somewhat annoying in generic code.

@SuppressWarnings("unchecked")
public <E extends Enum<E>> E[] getValues(Class<E> clazz, String[] strings) {
  E[] result = (E[])java.lang.reflect.Array.newInstance(clazz, strings.length);
  for (int i = 0; i < strings.length; ++i) {
    result[i] = Enum.valueOf(clazz, strings[i]);
  }
  return result;
}

This should work.

Enums in Java are very powerful. Since enumerations are constant and cannot be dynamically added, you could do something like this:

public enum Race {
    ELVES, HUMANS, DWARFS;

    public static Race getValue(String name) {
        switch (name.toLowerCase()) {
            case "evles": return EVLES;
            case "humans": return HUMANS;
            case "dwarfs": return DWARFS;
            default: throw new Exception();
        }
    }
}

This assumes you're using Java 7, but if not, replace the switch with else-if statements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM