J'ai un problème en Java avec Enums . J'ai lu la documentation sur l'affectation de paramètres de valeur à Enums . Mais ma question est de savoir ce qui concerne les valeurs multiples, est-ce possible?
C'est ce que j'aimerais réaliser: J'ai un Enum pour les langues. Chaque langue est représentée par son nom et par quelques alias plus courts (pas toujours, et pas toujours le même nombre d'alias)
Voici un exemple:
public enum Language{
English("english", "eng", "en", "en_GB", "en_US"),
German("german", "de", "ge"),
Croatian("croatian", "hr", "cro"),
Russian("russian")
}
Puis-je simplement définir un Enum comme celui-ci et obtenir les bonnes valeurs d'énum en appelant Language.valueOf () ???
Ceci est probablement similaire à ce que vous essayez d'atteindre.
public enum Language{
English("english", "eng", "en", "en_GB", "en_US"),
German("german", "de", "ge"),
Croatian("croatian", "hr", "cro"),
Russian("russian");
private final List<String> values;
Language(String ...values) {
this.values = Arrays.asList(values);
}
public List<String> getValues() {
return values;
}
}
Rappelez-vous que les enums sont une classe comme les autres; English("english", "eng", "en", "en_GB", "en_US")
appelle le constructeur enum.
Vous pouvez ensuite récupérer la valeur enum correspondant à une chaîne par le biais d'une méthode de recherche (vous pouvez la redéfinir en tant que méthode statique).
public static Language find(String name) {
for (Language lang : Language.values()) {
if (lang.getValues().contains(name)) {
return lang;
}
}
return null;
}
Le mappage d'une chaîne sur une valeur enum correspond généralement à ce que la méthode statique valueOf
fait pour vous. Donc, si vous voulez accomplir cela avec l'utilisation de synonymes, vous devrez développer quelque chose de similaire. Cependant, nous ne voulons pas donner à la présence la possibilité de remplacer une méthode statique, nous la nommons donc différente pour ce but: fromString
devrait être approprié.
public enum Language {
ENGLISH("eng", "en", "en_GB", "en_US"),
GERMAN("de", "ge"),
CROATIAN("hr", "cro"),
RUSSIAN("ru"),
BELGIAN("be",";-)");
static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>();
static {
for (Language language:Language.values()) {
// ignoring the case by normalizing to uppercase
ALIAS_MAP.put(language.name().toUpperCase(),language);
for (String alias:language.aliases)
ALIAS_MAP.put(alias.toUpperCase(),language);
}
}
static public boolean has(String value) {
// ignoring the case by normalizing to uppercase
return ALIAS_MAP.containsKey(value.toUpperCase());
}
static public Language fromString(String value) {
if (value == null) throw new NullPointerException("alias null");
Language language = ALIAS_MAP.get(value);
if (language == null)
throw new IllegalArgumentException("Not an alias: "+value);
return language;
}
private List<String> aliases;
private Language(String... aliases) {
this.aliases = Arrays.asList(aliases);
}
}
Comme avantage de ce type d'implémentation, nous pouvons, comme démontré, implémenter aussi facilement la méthode statique has
pour vérifier si un alias donné fait partie de l'ensemble de valeurs enum. Dans le même temps, nous avons appliqué de bonnes conventions de dénomination:
Notez qu'il n'est pas nécessaire de répéter le nom de la valeur enum elle-même: nous considérons toujours son propre nom automatiquement (il est ajouté à ALIAS_MAP), et nous normalisons tout en majuscule pour le rendre insensible à la casse.
Ça semble gros, mais en utilisant l'énum, ça a l'air joli:
public void main() {
Language myLanguage = Language.fromString("en_GB");
if (myLanguage == Language.ENGLISH) {
System.out.println("Yes, I know, you understand English!");
}
}
Le conteneur de support des alias est une Map
, une HashMap
pour être plus spécifique. La HashMap
fournit un chemin d'accès rapide aux alias et est également facile à développer. Chaque fois que nous pensons à «indexer» quelque chose, une HashMap
devrait être notre premier choix.
Notez que pour une utilisation transparente, nous stockons à la fois le nom de la constante d’énumération elle-même (récupérée via la méthode name()
) et tous les alias. Nous aurions pu implémenter cela différemment en essayant d'abord d'effectuer la recherche à l'aide de la méthode valueOf
intégrée intégrée. C'est un choix de conception, mais nous aurions potentiellement à traiter avec des exceptions supplémentaires, etc.
Bref non.
Le paramètre de la méthode valueOf () doit être uniquement la chaîne du type constant enum. Donc, il ne peut pas varier, ou rechercher des valeurs possibles. Voir le JavaDoc .
Vous devez écrire votre propre méthode d’utilitaire pour renvoyer le type d’énum approprié pour les valeurs données.
Normaliser les données:
public enum LanguageCode
{
ENGLISH,
GERMAN,
CROATIAN,
RUSSIAN,
// ...
}
// (add whatever initialization you want to that
Ensuite
public enum Language{
english(ENGLISH),
eng(ENGLISH),
en(ENGLISH),
en_GB(ENGLISH),
// ...
}
etc.
Wow, réponse très rapide:) Merci les gars.
Andy a raison. Je souhaite appeler Language.valueOf ("eng") ou Language.valueOf ("anglais") et obtenir Language.English as return.
J'ai déjà une fonction utilitaire qui fait cela, mais ce n'est pas très gentil . Fonction de commutation qui vérifie les valeurs de chaîne et renvoie l'instance enum appropriée.
Mais il y a beaucoup de réécriture de code (j'ai environ 30 à 40 langues) ..__ Et si je veux ajouter une langue, je dois l'ajouter à enum et implémenter un nouveau contrôle dans la classe utilitaire.
Je vais essayer l'approche de Flavios ... Une seule question ... Votre constructeur ne devrait-il pas en être ainsi?
Language(List<String> values) {
this.values = Arrays.asList(values);
}
Vous pouvez également ajouter une méthode pour que vos enums et votre constructeur soient plus propres si la structure est plus compliquée:
public Language getLanguage(String code){
switch(code){
case "en":
case "en_GB":
...
case "eng":
return ENGLISH;
case "rus":
case "russian":
return RUSSIAN;
}
}