J'ai l'énumération suivante
enum Animal implements Mammal {
CAT, DOG;
public static Mammal findMammal(final String type) {
for (Animal a : Animal.values()) {
if (a.name().equals(type)) {
return a;
}
}
}
}
J'avais initialement utilisé la Enum.valueOf(Animal.class, "DOG");
pour trouver un animal en particulier. Cependant, je ne savais pas que si aucune correspondance n'était trouvée, une variable IllegalArgumentException
était lancée. Je pensais que peut-être un null a été retourné. Cela me pose donc un problème. Je ne veux pas attraper cette IllegalArgumentException
si une correspondance n'est pas trouvée. Je veux être capable de rechercher toutes les énumérations de type Mammal
et je ne veux pas avoir à implémenter cette statique 'findMammal
' pour chaque énumération de type Mammal
. Ma question est donc la suivante: quelle serait la décision de conception la plus propice pour mettre en œuvre ce comportement? Je vais avoir un code d'appel comme ceci:
public class Foo {
public Mammal bar(final String arg) {
Mammal m = null;
if (arg.equals("SomeValue")) {
m = Animal.findMammal("CAT");
} else if (arg.equals("AnotherValue") {
m = Human.findMammal("BILL");
}
// ... etc
}
}
Comme vous pouvez le constater, j'ai différents types de mammifères - «animaux», «humains», qui sont des enums. Je ne veux pas avoir à implémenter 'findMammal' pour chaque énumération de mammifères. Je suppose que le meilleur pari est simplement de créer une classe d’utilité qui prend un argument de mammifère et cherche cela? Peut-être qu'il y a une solution plus ordonnée.
Pourquoi ne pas créer un HashMap<String, Mammal>
? Il suffit de le faire une fois ...
public class Foo {
private static final Map<String, Mammal> NAME_TO_MAMMAL_MAP;
static {
NAME_TO_MAMMAL_MAP = new HashMap<String, Mammal>();
for (Human human : EnumSet.allOf(Human.class)) {
NAME_TO_MAMMAL_MAP.put(human.name(), human);
}
for (Animal animal : EnumSet.allOf(Animal.class)) {
NAME_TO_MAMMAL_MAP.put(animal.name(), animal);
}
}
public static Mammal bar(final String arg) {
return NAME_TO_MAMMAL_MAP.get(arg);
}
}
Remarques:
null
si le nom n'existe pasSi vous ne voulez pas toucher chaque Enum (compréhensible), une méthode utilitaire est la voie à suivre. Je comprends ne pas vouloir attraper l’exception dans votre code, mais l’attraper dans la méthode devrait bien se passer, cependant:
public static <T extends Enum<T>> T findEnumValue(Class<T> type, String name) {
if (name == null)
return null;
try {
return Enum.valueOf(type, name.toUpperCase());
} catch (IllegalArgumentException iae) {
return null;
}
}
Vous pouvez utiliser la bibliothèque de goyave. Enums class permet cela:
Enums.valueOfFunction(MyEnum.class).apply(id);
Je ne comprends pas la question mais j'avais également besoin d'une valueOf
qui retourne null
au lieu de lancer une exception. J'ai donc créé cette méthode d'utilitaire:
public static <T extends Enum<T>> T valueOf(T[] values, String name)
{
for (T value : values) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
Vous pourriez l'appeler comme ça:
Animal a = valueOf(Animal.values(), "CAT");
Vous avez une erreur dans votre code. Si vous avez besoin que votre fonction renvoie null lorsqu'elle ne trouve pas quelque chose, retournez-la simplement:
enum Animal implements Mammal {
CAT, DOG;
public static Mammal findMammal(final String type) {
for (Animal a : Animal.values()) {
if (a.name().equals(type)) {
return a;
}
}
return null; // this line works if nothing is found.
}
}
Aucune technologie ne vous aidera si vous faites la même erreur et oubliez de créer une valeur de retour pour chaque cas possible.
Votre choix: Enum - EnumMaps - HashMap dépend de la dynamique de vos données. Les constantes Enums ne peuvent pas être créées au moment de l'exécution. D'autre part, vous n'avez pas besoin de vérifier beaucoup de choses au runtime - le compilateur le fera. Et vous oublierez très probablement de vérifier quelque chose. Ce que Jon Skeet gère facilement pourrait vous donner mal à la tête.
Si vous pouvez dire
m = Animal.findMammal("CAT");
Pourquoi ne peux-tu pas dire
m = Animal.CAT;
Le "CAT" devra quand même correspondre au nom de l'énum. Dans votre exemple, "CAT" n'est pas dérivé d'un paramètre mais est codé en dur.
UPDATE(peut-être plus au fait de la question)
C'est un peu élaboré, mais ...
public interface Mammal{
public void doMammalStuff();
public static interface Finder{
public Mammal find(String name, Class<Enum<?>> enumType);
}
public static Finder FINDER = new Finder(){
public Mammal find(String name, Class<Enum<?>> enumType) {
return enumType.forName( name );
};
};
}
Ensuite, vous pouvez appeler
Mammal m = Mammal.Finder.find( "CAT", Animal.class );
Votre implémentation de find () peut avoir un aspect différent (c’est-à-dire ne pas lancer d’exception).