Java Language
Enums
Recherche…
Introduction
enum
Java (déclarées à l'aide du mot-clé enum
) sont une syntaxe abrégée pour des quantités importantes de constantes d'une même classe.
Syntaxe
- [public / protected / private] enum Nom_enum {// Déclarez une nouvelle énumération.
- ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Déclarez les constantes enum. Ce doit être la première ligne à l'intérieur de l'énumération et doit être séparé par des virgules, avec un point-virgule à la fin.
- ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Déclarez les constantes enum avec des paramètres. Les types de paramètres doivent correspondre au constructeur.
- ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Déclarez les constantes enum avec des méthodes surchargées. Cela doit être fait si l'énumération contient des méthodes abstraites; toutes ces méthodes doivent être mises en œuvre.
- ENUM_CONSTANT.name () // Retourne une chaîne avec le nom de la constante enum.
- ENUM_CONSTANT.ordinal () // Renvoie l'ordinal de cette constante d'énumération, sa position dans sa déclaration enum, où la constante initiale reçoit un ordinal de zéro.
- Enum_name.values () // Retourne un nouveau tableau (de type Enum_name []) contenant chaque constante de cette enum chaque fois qu'il est appelé.
- Enum_name.valueOf ("ENUM_CONSTANT") // Inverse de ENUM_CONSTANT.name () - renvoie la constante enum avec le nom donné.
- Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Un synonyme du précédent: L'inverse de ENUM_CONSTANT.name () - renvoie la constante enum avec le nom donné.
Remarques
Restrictions
Les énumérations étendent toujours java.lang.Enum
, il est donc impossible pour un enum d'étendre une classe. Cependant, ils peuvent implémenter de nombreuses interfaces.
Conseils & Astuces
En raison de leur représentation spécialisée, il existe des cartes et des ensembles plus efficaces qui peuvent être utilisés avec des énumérations comme clés. Celles-ci courent souvent plus vite que leurs homologues non spécialisés.
Déclarer et utiliser un enum de base
Enum peut être considéré comme du sucre syntaxique pour une classe scellée qui n'est instanciée que plusieurs fois au moment de la compilation pour définir un ensemble de constantes.
Un simple enum pour énumérer les différentes saisons serait déclaré comme suit:
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Bien que les constantes enum ne doivent pas nécessairement être en majuscules, la convention Java stipule que les noms des constantes sont entièrement en majuscules, les mots étant séparés par des traits de soulignement.
Vous pouvez déclarer un Enum dans son propre fichier:
/**
* This enum is declared in the Season.java file.
*/
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Mais vous pouvez également le déclarer dans une autre classe:
public class Day {
private Season season;
public String getSeason() {
return season.name();
}
public void setSeason(String season) {
this.season = Season.valueOf(season);
}
/**
* This enum is declared inside the Day.java file and
* cannot be accessed outside because it's declared as private.
*/
private enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
}
Enfin, vous ne pouvez pas déclarer un Enum dans un corps de méthode ou un constructeur:
public class Day {
/**
* Constructor
*/
public Day() {
// Illegal. Compilation error
enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
}
public void aSimpleMethod() {
// Legal. You can declare a primitive (or an Object) inside a method. Compile!
int primitiveInt = 42;
// Illegal. Compilation error.
enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
Season season = Season.SPRING;
}
}
Les constantes énumérées en double ne sont pas autorisées:
public enum Season {
WINTER,
WINTER, //Compile Time Error : Duplicate Constants
SPRING,
SUMMER,
FALL
}
Chaque constante d'énum est public
, static
et final
par défaut. Comme chaque constante est static
, il est possible d'y accéder directement en utilisant le nom enum.
Les constantes enum peuvent être transmises comme paramètres de méthode:
public static void display(Season s) {
System.out.println(s.name()); // name() is a built-in method that gets the exact name of the enum constant
}
display(Season.WINTER); // Prints out "WINTER"
Vous pouvez obtenir un tableau des constantes enum en utilisant la méthode values()
. Les valeurs sont garanties dans l'ordre de déclaration dans le tableau renvoyé:
Season[] seasons = Season.values();
Remarque: cette méthode alloue un nouveau tableau de valeurs à chaque appel.
Pour parcourir les constantes énumérées:
public static void enumIterate() {
for (Season s : Season.values()) {
System.out.println(s.name());
}
}
Vous pouvez utiliser des énumérations dans une déclaration de switch
:
public static void enumSwitchExample(Season s) {
switch(s) {
case WINTER:
System.out.println("It's pretty cold");
break;
case SPRING:
System.out.println("It's warming up");
break;
case SUMMER:
System.out.println("It's pretty hot");
break;
case FALL:
System.out.println("It's cooling down");
break;
}
}
Vous pouvez également comparer les constantes énumérées en utilisant ==
:
Season.FALL == Season.WINTER // false
Season.SPRING == Season.SPRING // true
Une autre façon de comparer les constantes d'énumération consiste à utiliser les equals()
comme ci-dessous, ce qui est considéré comme une mauvaise pratique car vous pouvez facilement tomber dans des pièges comme suit:
Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error
De plus, bien que l'ensemble d'instances dans l' enum
ne puisse pas être modifié au moment de l'exécution, les instances elles-mêmes ne sont pas intrinsèquement immuables car, comme toute autre classe, une enum
peut contenir des champs mutables.
public enum MutableExample {
A,
B;
private int count = 0;
public void increment() {
count++;
}
public void print() {
System.out.println("The count of " + name() + " is " + count);
}
}
// Usage:
MutableExample.A.print(); // Outputs 0
MutableExample.A.increment();
MutableExample.A.print(); // Outputs 1 -- we've changed a field
MutableExample.B.print(); // Outputs 0 -- another instance remains unchanged
Cependant, une bonne pratique consiste à rendre les instances d' enum
immuables, c'est-à-dire que lorsqu'elles n'ont pas de champs supplémentaires ou que tous ces champs sont marqués comme final
et qu'ils sont immuables eux-mêmes. Cela garantira que pour une durée de vie de l'application, une enum
ne enum
pas de mémoire et qu'il est prudent d'utiliser ses instances sur tous les threads.
Enums implémentent implicitement Serializable
et Comparable
car la classe Enum
fait:
public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable
Enums avec des constructeurs
Un enum
ne peut pas avoir de constructeur public; cependant, les constructeurs privés sont acceptables (les constructeurs pour les énumérations sont package-private par défaut):
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25); // usual names for US coins
// note that the above parentheses and the constructor arguments match
private int value;
Coin(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
int p = Coin.NICKEL.getValue(); // the int value will be 5
Il est recommandé de garder tous les champs privés et de fournir des méthodes de lecture, car il existe un nombre fini d'instances pour un enum.
Si vous deviez implémenter un Enum
tant que class
, cela ressemblerait à ceci:
public class Coin<T extends Coin<T>> implements Comparable<T>, Serializable{
public static final Coin PENNY = new Coin(1);
public static final Coin NICKEL = new Coin(5);
public static final Coin DIME = new Coin(10);
public static final Coin QUARTER = new Coin(25);
private int value;
private Coin(int value){
this.value = value;
}
public int getValue() {
return value;
}
}
int p = Coin.NICKEL.getValue(); // the int value will be 5
Les constantes enum sont techniquement modifiables, donc un setter pourrait être ajouté pour modifier la structure interne d'une constante enum. Cependant, ceci est considéré comme une très mauvaise pratique et devrait être évité.
La meilleure pratique consiste à rendre les champs Enum immuables, avec en final
:
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
private final int value;
Coin(int value){
this.value = value;
}
...
}
Vous pouvez définir plusieurs constructeurs dans le même enum. Lorsque vous le faites, les arguments que vous transmettez dans votre déclaration enum déterminent quel constructeur est appelé:
public enum Coin {
PENNY(1, true), NICKEL(5, false), DIME(10), QUARTER(25);
private final int value;
private final boolean isCopperColored;
Coin(int value){
this(value, false);
}
Coin(int value, boolean isCopperColored){
this.value = value;
this.isCopperColored = isCopperColored;
}
...
}
Remarque: Tous les champs d'énumération non primitifs doivent implémenter Serializable
car la classe Enum
fait.
Utiliser des méthodes et des blocs statiques
Un enum peut contenir une méthode, comme toute classe. Pour voir comment cela fonctionne, nous allons déclarer un enum comme ceci:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
}
Ayons une méthode qui renvoie l'enum dans la direction opposée:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
public Direction getOpposite(){
switch (this){
case NORTH:
return SOUTH;
case SOUTH:
return NORTH;
case WEST:
return EAST;
case EAST:
return WEST;
default: //This will never happen
return null;
}
}
}
Cela peut être amélioré grâce à l'utilisation de champs et de blocs d'initialisation statiques:
public enum Direction {
NORTH, SOUTH, EAST, WEST;
private Direction opposite;
public Direction getOpposite(){
return opposite;
}
static {
NORTH.opposite = SOUTH;
SOUTH.opposite = NORTH;
WEST.opposite = EAST;
EAST.opposite = WEST;
}
}
Dans cet exemple, la direction opposée est stockée dans un champ d'instance privé opposite
, qui est initialisé statiquement la première fois qu'une Direction
est utilisée. Dans ce cas particulier (parce que NORTH
référence SOUTH
et inversement), nous ne pouvons pas utiliser des énumérations avec les NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST)
opposite
constructeurs ici (Constructors DU NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST)
serait plus élégant et permettrait en opposite
de être déclarée final
, mais serait auto-référentielle et donc non autorisée).
Implémente l'interface
C'est une enum
qui est également une fonction appelable qui teste les entrées de String
contre des modèles d'expression régulière précompilés.
import java.util.function.Predicate;
import java.util.regex.Pattern;
enum RegEx implements Predicate<String> {
UPPER("[A-Z]+"), LOWER("[a-z]+"), NUMERIC("[+-]?[0-9]+");
private final Pattern pattern;
private RegEx(final String pattern) {
this.pattern = Pattern.compile(pattern);
}
@Override
public boolean test(final String input) {
return this.pattern.matcher(input).matches();
}
}
public class Main {
public static void main(String[] args) {
System.out.println(RegEx.UPPER.test("ABC"));
System.out.println(RegEx.LOWER.test("abc"));
System.out.println(RegEx.NUMERIC.test("+111"));
}
}
Chaque membre du enum peut également implémenter la méthode:
import java.util.function.Predicate;
enum Acceptor implements Predicate<String> {
NULL {
@Override
public boolean test(String s) { return s == null; }
},
EMPTY {
@Override
public boolean test(String s) { return s.equals(""); }
},
NULL_OR_EMPTY {
@Override
public boolean test(String s) { return NULL.test(s) || EMPTY.test(s); }
};
}
public class Main {
public static void main(String[] args) {
System.out.println(Acceptor.NULL.test(null)); // true
System.out.println(Acceptor.EMPTY.test("")); // true
System.out.println(Acceptor.NULL_OR_EMPTY.test(" ")); // false
}
}
Enum Polymorphism Pattern
Lorsqu'une méthode doit accepter un ensemble "extensible" de valeurs d' enum
, le programmeur peut appliquer un polymorphisme comme sur une class
normale en créant une interface qui sera utilisée n'importe où où l' enum
sera utilisée:
public interface ExtensibleEnum {
String name();
}
De cette façon, toute enum
étiquetée par (implémentant) l'interface peut être utilisée comme paramètre, permettant au programmeur de créer une quantité variable d' enum
qui sera acceptée par la méthode. Cela peut être utile, par exemple, dans les API où il existe une enum
par défaut (non modifiable) et où l'utilisateur de ces API souhaite "étendre" l' enum
avec plus de valeurs.
Un ensemble de valeurs enum par défaut peut être défini comme suit:
public enum DefaultValues implements ExtensibleEnum {
VALUE_ONE, VALUE_TWO;
}
Des valeurs supplémentaires peuvent alors être définies comme ceci:
public enum ExtendedValues implements ExtensibleEnum {
VALUE_THREE, VALUE_FOUR;
}
Exemple qui montre comment utiliser les énumérations - notez comment printEnum()
accepte les valeurs des deux types enum
:
private void printEnum(ExtensibleEnum val) {
System.out.println(val.name());
}
printEnum(DefaultValues.VALUE_ONE); // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO); // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR); // VALUE_FOUR
Remarque: Ce modèle ne vous empêche pas de redéfinir les valeurs enum, qui sont déjà définies dans une enum, dans une autre énumération. Ces valeurs enum seraient alors des instances différentes. De plus, il n'est pas possible d'utiliser switch-on-enum car nous n'avons que l'interface, pas le véritable enum
.
Enums avec des méthodes abstraites
Enums peut définir des méthodes abstraites, que chaque membre enum
doit implémenter.
enum Action {
DODGE {
public boolean execute(Player player) {
return player.isAttacking();
}
},
ATTACK {
public boolean execute(Player player) {
return player.hasWeapon();
}
},
JUMP {
public boolean execute(Player player) {
return player.getCoordinates().equals(new Coordinates(0, 0));
}
};
public abstract boolean execute(Player player);
}
Cela permet à chaque membre enum de définir son propre comportement pour une opération donnée, sans avoir à activer les types dans une méthode de la définition de niveau supérieur.
Notez que ce modèle est une forme abrégée de ce qui est généralement obtenu en utilisant des interfaces de polymorphisme et / ou d'implémentation.
Documenter les enums
Le nom enum
n'est pas toujours suffisamment clair pour être compris. Pour documenter un enum
, utilisez javadoc standard:
/**
* United States coins
*/
public enum Coins {
/**
* One-cent coin, commonly known as a penny,
* is a unit of currency equaling one-hundredth
* of a United States dollar
*/
PENNY(1),
/**
* A nickel is a five-cent coin equaling
* five-hundredth of a United States dollar
*/
NICKEL(5),
/**
* The dime is a ten-cent coin refers to
* one tenth of a United States dollar
*/
DIME(10),
/**
* The quarter is a US coin worth 25 cents,
* one-fourth of a United States dollar
*/
QUARTER(25);
private int value;
Coins(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
Obtenir les valeurs d'un enum
Chaque classe enum contient une méthode statique implicite nommée values()
. Cette méthode retourne un tableau contenant toutes les valeurs de cette enum. Vous pouvez utiliser cette méthode pour parcourir les valeurs. Il est important de noter toutefois que cette méthode retourne un nouveau tableau à chaque appel.
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
/**
* Print out all the values in this enum.
*/
public static void printAllDays() {
for(Day day : Day.values()) {
System.out.println(day.name());
}
}
}
Si vous avez besoin d'un Set
vous pouvez également utiliser EnumSet.allOf(Day.class)
.
Enum comme paramètre de type borné
Lors de l'écriture d'une classe avec des génériques dans Java, il est possible de s'assurer que le paramètre type est une énumération. Comme toutes les énumérations étendent la classe Enum
, la syntaxe suivante peut être utilisée.
public class Holder<T extends Enum<T>> {
public final T value;
public Holder(T init) {
this.value = init;
}
}
Dans cet exemple, le type T
doit être un enum.
Obtenir un enum constant par nom
Disons que nous avons une énumération DayOfWeek
:
enum DayOfWeek {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}
Un enum est compilé avec une méthode static valueOf()
intégrée qui peut être utilisée pour rechercher une constante par son nom:
String dayName = DayOfWeek.SUNDAY.name();
assert dayName.equals("SUNDAY");
DayOfWeek day = DayOfWeek.valueOf(dayName);
assert day == DayOfWeek.SUNDAY;
Ceci est également possible en utilisant un type enum dynamique:
Class<DayOfWeek> enumType = DayOfWeek.class;
DayOfWeek day = Enum.valueOf(enumType, "SUNDAY");
assert day == DayOfWeek.SUNDAY;
Ces deux méthodes valueOf()
lancent une IllegalArgumentException
si l'énumération spécifiée n'a pas de constante avec un nom correspondant.
La bibliothèque Guava fournit une méthode d'assistance Enums.getIfPresent()
qui retourne une Optional
Guava pour éliminer la gestion des exceptions explicites:
DayOfWeek defaultDay = DayOfWeek.SUNDAY;
DayOfWeek day = Enums.valueOf(DayOfWeek.class, "INVALID").or(defaultDay);
assert day == DayOfWeek.SUNDAY;
Implémenter le modèle Singleton avec une énumération à un seul élément
Les constantes enum sont instanciées quand une énumération est référencée pour la première fois. Par conséquent, cela permet d'implémenter le modèle de conception du logiciel Singleton avec un enum à élément unique.
public enum Attendant {
INSTANCE;
private Attendant() {
// perform some initialization routine
}
public void sayHello() {
System.out.println("Hello!");
}
}
public class Main {
public static void main(String... args) {
Attendant.INSTANCE.sayHello();// instantiated at this point
}
}
Selon le livre "Effective Java" de Joshua Bloch, une énumération à un seul élément est le meilleur moyen d'implémenter un singleton. Cette approche présente les avantages suivants:
- sécurité du fil
- garantie d'instanciation unique
- sérialisation prête à l'emploi
Et comme le montre la section implémente l'interface, ce singleton pourrait également implémenter une ou plusieurs interfaces.
Enum avec des propriétés (champs)
Dans le cas où nous souhaitons utiliser enum
avec plus d'informations et pas seulement comme des valeurs constantes, nous voulons pouvoir comparer deux énumérations.
Prenons l'exemple suivant:
public enum Coin {
PENNY(1), NICKEL(5), DIME(10), QUARTER(25);
private final int value;
Coin(int value){
this.value = value;
}
public boolean isGreaterThan(Coin other){
return this.value > other.value;
}
}
Ici, nous avons défini un Enum
appelé Coin
qui représente sa valeur. Avec la méthode isGreaterThan
on peut comparer deux enum
s:
Coin penny = Coin.PENNY;
Coin dime = Coin.DIME;
System.out.println(penny.isGreaterThan(dime)); // prints: false
System.out.println(dime.isGreaterThan(penny)); // prints: true
Convertir enum en String
Parfois, vous souhaitez convertir votre enum en une chaîne, il y a deux façons de le faire.
Supposons que nous ayons:
public enum Fruit {
APPLE, ORANGE, STRAWBERRY, BANANA, LEMON, GRAPE_FRUIT;
}
Alors, comment pouvons-nous convertir quelque chose comme Fruit.APPLE
en "APPLE"
?
Convertir en utilisant le name()
name()
est une méthode interne à enum
qui renvoie la représentation String
de l'énumération, la String
retour représente exactement comment la valeur enum a été définie.
Par exemple:
System.out.println(Fruit.BANANA.name()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"
Convertir en utilisant toString()
toString()
est, par défaut , remplacé pour avoir le même comportement que name()
Cependant, toString()
est probablement surchargée par les développeurs pour faire imprimer un plus convivial utilisateur String
N'utilisez pas
toString()
si vous voulez effectuer un archivage de votre code,name()
est beaucoup plus stable pour cela.toString()
lorsque vous allez afficher la valeur dans les journaux ou la sortie standard ou quelque chose
Par défaut:
System.out.println(Fruit.BANANA.toString()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"
Exemple de dépassement
System.out.println(Fruit.BANANA.toString()); // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"
Enum corps spécifique constant
Dans un enum
il est possible de définir un comportement spécifique pour une constante particulière de l' enum
qui remplace le comportement par défaut de l' enum
. Cette technique est appelée corps spécifique constant .
Supposons que trois élèves de piano - John, Ben et Luke - soient définis dans une enum
appelée PianoClass
, comme suit:
enum PianoClass {
JOHN, BEN, LUKE;
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
Et un jour, deux autres étudiants arrivent - Rita et Tom - avec un sexe (féminin) et un niveau (intermédiaire) qui ne correspondent pas aux précédents:
enum PianoClass2 {
JOHN, BEN, LUKE, RITA, TOM;
public String getSex() {
return "Male"; // issue, Rita is a female
}
public String getLevel() {
return "Beginner"; // issue, Tom is an intermediate student
}
}
de sorte que le simple ajout des nouveaux étudiants à la déclaration constante, comme suit, n'est pas correct:
PianoClass2 tom = PianoClass2.TOM;
PianoClass2 rita = PianoClass2.RITA;
System.out.println(tom.getLevel()); // prints Beginner -> wrong Tom's not a beginner
System.out.println(rita.getSex()); // prints Male -> wrong Rita's not a male
Il est possible de définir un comportement spécifique pour chaque constante, Rita et Tom, qui remplace le comportement par défaut de PianoClass2
comme suit:
enum PianoClass3 {
JOHN, BEN, LUKE,
RITA {
@Override
public String getSex() {
return "Female";
}
},
TOM {
@Override
public String getLevel() {
return "Intermediate";
}
};
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
et maintenant le niveau de Tom et le sexe de Rita sont comme ils devraient être:
PianoClass3 tom = PianoClass3.TOM;
PianoClass3 rita = PianoClass3.RITA;
System.out.println(tom.getLevel()); // prints Intermediate
System.out.println(rita.getSex()); // prints Female
Une autre façon de définir un corps spécifique au contenu consiste à utiliser un constructeur, par exemple:
enum Friend {
MAT("Male"),
JOHN("Male"),
JANE("Female");
private String gender;
Friend(String gender) {
this.gender = gender;
}
public String getGender() {
return this.gender;
}
}
et utilisation:
Friend mat = Friend.MAT;
Friend john = Friend.JOHN;
Friend jane = Friend.JANE;
System.out.println(mat.getGender()); // Male
System.out.println(john.getGender()); // Male
System.out.println(jane.getGender()); // Female
Zéro instance enum
enum Util {
/* No instances */;
public static int clamp(int min, int max, int i) {
return Math.min(Math.max(i, min), max);
}
// other utility methods...
}
Tout comme enum
peut être utilisé pour les singletons (1 classe d'instance), il peut être utilisé pour les classes d'utilitaires (0 classes d'instance). Veillez simplement à terminer la liste (vide) des constantes enum avec un ;
.
Voir la question Énumération d'instance zéro vs constructeurs privés pour empêcher l'instanciation d'une discussion sur les avantages et les inconvénients par rapport aux constructeurs privés.
Enums avec des champs statiques
Si votre classe enum doit avoir des champs statiques, gardez à l'esprit qu'ils sont créés après les valeurs enum elles-mêmes. Cela signifie que le code suivant entraînera une NullPointerException
:
enum Example {
ONE(1), TWO(2);
static Map<String, Integer> integers = new HashMap<>();
private Example(int value) {
integers.put(this.name(), value);
}
}
Un moyen possible de résoudre ce problème:
enum Example {
ONE(1), TWO(2);
static Map<String, Integer> integers;
private Example(int value) {
putValue(this.name(), value);
}
private static void putValue(String name, int value) {
if (integers == null)
integers = new HashMap<>();
integers.put(name, value);
}
}
Ne pas initialiser le champ statique:
enum Example {
ONE(1), TWO(2);
// after initialisisation integers is null!!
static Map<String, Integer> integers = null;
private Example(int value) {
putValue(this.name(), value);
}
private static void putValue(String name, int value) {
if (integers == null)
integers = new HashMap<>();
integers.put(name, value);
}
// !!this may lead to null poiner exception!!
public int getValue(){
return (Example.integers.get(this.name()));
}
}
initialisation:
- créer les valeurs enum
- comme effet secondaire appelé putValue () qui initialise les entiers
- les valeurs statiques sont définies
- integers = null; // est exécuté après les énumérations pour que le contenu des entiers soit perdu
Comparer et contient les valeurs Enum
Enums ne contient que des constantes et peut être comparé directement avec ==
. Donc, seule la vérification de référence est nécessaire, pas besoin d'utiliser la méthode .equals
. De plus, si les .equals
utilisées de manière incorrecte, peuvent générer l' NullPointerException
alors que ce n'est pas le cas avec la vérification ==
.
enum Day {
GOOD, AVERAGE, WORST;
}
public class Test {
public static void main(String[] args) {
Day day = null;
if (day.equals(Day.GOOD)) {//NullPointerException!
System.out.println("Good Day!");
}
if (day == Day.GOOD) {//Always use == to compare enum
System.out.println("Good Day!");
}
}
}
Pour grouper, compléter, EnumSet
valeurs enum, nous avons la classe EnumSet
qui contient différentes méthodes.
EnumSet#range
: Pour obtenir un sous-ensemble d'énum par plage définie par deux points de terminaisonEnumSet#of
: Ensemble deEnumSet#of
spécifiques sans aucune plage. Plusieurs surchargeof
méthodes sont là.EnumSet#complementOf
: ensemble d'énum complément des valeurs enum fournies dans le paramètre methodenum Page { A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 } public class Test { public static void main(String[] args) { EnumSet<Page> range = EnumSet.range(Page.A1, Page.A5); if (range.contains(Page.A4)) { System.out.println("Range contains A4"); } EnumSet<Page> of = EnumSet.of(Page.A1, Page.A5, Page.A3); if (of.contains(Page.A1)) { System.out.println("Of contains A1"); } } }