Les Enums Java
Définissez un ensemble fixe de constantes en Java avec les types enum, y compris les enums avec champs, constructeurs et méthodes.
Un enum est une classe dont les instances constituent un ensemble fixe de valeurs connues à la compilation. Les jours de la semaine, les couleurs d'un feu de circulation, les statuts de commande — tout ce pour quoi les valeurs autorisées forment une petite liste nommée. Une fois que vous écrivez enum Status { OPEN, CLOSED }, ces deux valeurs sont les seules valeurs Status qui existeront jamais, et le compilateur vous le signalera si vous tentez d'en inventer une troisième.
Les enums remplacent l'ancienne habitude C du public static final int OPEN = 0;. Les constantes entières n'offrent aucune sécurité de type — setStatus(7) compile — mais setStatus(Status status) n'accepte qu'une des valeurs déclarées.
Déclarer un enum
La forme la plus simple est juste une liste de noms de constantes :
public enum Direction {
NORTH, EAST, SOUTH, WEST
}Utilisez-le comme n'importe quel autre type :
Direction d = Direction.NORTH;
if (d == Direction.NORTH) System.out.println("heading up");Chaque constante est une instance singleton de Direction. La comparaison avec == est correcte et idiomatique — il n'y a qu'un seul NORTH dans la JVM, donc l'égalité de référence correspond à l'égalité de valeur.
Dans un switch
Les enums et switch sont faits l'un pour l'autre :
switch (d) {
case NORTH -> System.out.println("up");
case SOUTH -> System.out.println("down");
case EAST, WEST -> System.out.println("sideways");
}Notez le NORTH nu au lieu de Direction.NORTH — à l'intérieur d'un switch sur un enum, le compilateur connaît le type. Si vous ajoutez une nouvelle constante et oubliez de la gérer dans une expression switch, vous obtiendrez une erreur de compilation pour non-exhaustivité, ce qui est exactement le filet de sécurité recherché.
Champs, constructeurs et méthodes
Un enum peut porter des données et des comportements. Chaque constante est construite avec des arguments, et le corps de l'enum peut définir des méthodes normales :
public enum Planet {
MERCURY(3.303e+23, 2.4397e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6);
private final double massKg;
private final double radiusM;
Planet(double massKg, double radiusM) {
this.massKg = massKg;
this.radiusM = radiusM;
}
public double surfaceGravity() {
final double G = 6.67300E-11;
return G * massKg / (radiusM * radiusM);
}
}Deux règles à retenir :
- La liste des constantes vient en premier dans le corps, séparée du reste par un point-virgule.
- Le constructeur est implicitement privé — les enums ne peuvent pas être instanciés depuis l'extérieur, ce qui est tout l'intérêt.
Méthodes intégrées
Chaque enum dispose gratuitement de quelques méthodes :
name()renvoie le nom déclaré de la constante sous forme deString.ordinal()renvoie sa position zéro-indexée dans la déclaration. Utile occasionnellement ; évitez de la persister car réordonner les constantes en change silencieusement la signification.values()renvoie un tableau de toutes les constantes dans l'ordre de déclaration — idéal pour les bouclesfor (Direction d : Direction.values()). Il construit un nouveau tableau à chaque appel, donc mettez-le en cache dans une variable locale si vous itérez dans une boucle critique.valueOf(String)recherche une constante par son nom exact (sensible à la casse) et lève uneIllegalArgumentExceptions'il n'y a pas de correspondance.
Comme valueOf lève une exception sur une entrée inconnue, protégez-le quand la chaîne provient de l'extérieur de votre code — saisie utilisateur, fichier, charge utile réseau :
Direction d = Direction.valueOf("EAST"); // EAST
try {
Direction.valueOf("UP"); // not a declared constant
} catch (IllegalArgumentException e) {
System.out.println("no such constant"); // no such constant
}Comportement par constante
Parfois une constante doit se comporter différemment des autres. Vous pouvez remplacer des méthodes par constante avec un corps anonyme :
public enum Operation {
PLUS { public int apply(int a, int b) { return a + b; } },
MINUS { public int apply(int a, int b) { return a - b; } },
TIMES { public int apply(int a, int b) { return a * b; } };
public abstract int apply(int a, int b);
}Chaque constante devient une petite sous-classe anonyme d'Operation qui implémente apply. L'aspect patron de stratégie est obtenu gratuitement.
Implémenter des interfaces
Les enums peuvent implémenter des interfaces — ils ne peuvent simplement pas étendre d'autres classes (ils étendent implicitement java.lang.Enum) :
public enum Day implements Runnable {
MONDAY, TUESDAY;
public void run() { System.out.println("today is " + name()); }
}C'est une manière propre de brancher une famille fixe de stratégies dans du code qui veut n'importe quel Runnable.
EnumSet et EnumMap
Lorsque vous avez besoin d'un Set ou d'une Map dont la clé est un enum, préférez EnumSet et EnumMap à HashSet/HashMap. Les deux sont supportés par un vecteur de bits ou un tableau simple dimensionné à l'enum, ce qui évite complètement le hachage — les recherches sont un simple index de tableau, et un EnumSet d'un petit enum tient dans un seul long :
EnumSet<Direction> horizontal = EnumSet.of(Direction.EAST, Direction.WEST);
EnumSet<Direction> all = EnumSet.allOf(Direction.class); // every constant
EnumSet<Direction> none = EnumSet.noneOf(Direction.class); // empty, ready to fill
EnumMap<Direction, String> labels = new EnumMap<>(Direction.class);
labels.put(Direction.NORTH, "up");L'itération sur un EnumSet ou EnumMap suit l'ordre de déclaration, ce qui rend leur sortie déterministe — une raison supplémentaire de les préférer aux collections basées sur le hachage.
Un exemple concret
Et ensuite
Les enums verrouillent un ensemble fixe d'instances. Le prochain chapitre présente une autre forme de classe restreinte — les records, conçus pour les porteurs de données immuables simples. Continuez vers Java records.