Obtenir une valeur d'enum à partir d'une chaîne en Java
Convertir une chaîne en valeur d'enum est une opération courante : lecture de paramètres, parsing JSON, configuration. Java fournit la méthode valueOf() intégrée, mais son comportement strict piège souvent les développeurs.
La méthode valueOf() générée par le compilateur
Tout enum Java hérite d'une méthode valueOf(String) statique, générée automatiquement :
public enum Jour {
LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE
}
Jour j = Jour.valueOf("LUNDI");
System.out.println(j); // LUNDI
La correspondance doit être exacte, casse comprise. "lundi" ou "Lundi" lèvent IllegalArgumentException.
Gérer le cas où la chaîne est invalide
try {
Jour j = Jour.valueOf("Dimanche");
} catch (IllegalArgumentException e) {
System.out.println("Jour inconnu");
} catch (NullPointerException e) {
System.out.println("Chaîne null");
}
Deux exceptions à prévoir : IllegalArgumentException si le nom n'existe pas, NullPointerException si la chaîne est null.
Version tolérante à la casse
Pour accepter n'importe quelle casse, ajoutez une méthode fromString à l'enum :
public enum Jour {
LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE;
public static Jour fromString(String s) {
if (s == null) return null;
return Jour.valueOf(s.trim().toUpperCase());
}
}
Version qui retourne Optional
Plutôt qu'une exception, renvoyez un Optional vide :
public static Optional<Jour> fromStringOptional(String s) {
if (s == null) return Optional.empty();
try {
return Optional.of(Jour.valueOf(s.trim().toUpperCase()));
} catch (IllegalArgumentException e) {
return Optional.empty();
}
}
// Utilisation
Jour j = Jour.fromStringOptional("lundi").orElse(Jour.LUNDI);
Faire correspondre un libellé différent du nom de constante
Souvent, on veut stocker en base un libellé plus lisible que LUNDI, ou supporter plusieurs alias. Attribuez un libellé à chaque constante :
public enum Jour {
LUNDI("lun"), MARDI("mar"), MERCREDI("mer"),
JEUDI("jeu"), VENDREDI("ven"), SAMEDI("sam"), DIMANCHE("dim");
private final String libelle;
Jour(String libelle) { this.libelle = libelle; }
public String libelle() { return libelle; }
public static Jour fromLibelle(String libelle) {
for (Jour j : values()) {
if (j.libelle.equalsIgnoreCase(libelle)) return j;
}
throw new IllegalArgumentException("Libellé inconnu : " + libelle);
}
}
Jour.fromLibelle("ven"); // VENDREDI
Cache pour de meilleures performances
Si l'enum a beaucoup de valeurs et que la conversion est fréquente (parsing de milliers de lignes), utilisez une Map préconstruite :
public enum Jour {
LUNDI("lun"), MARDI("mar"); /* … */
private static final Map<String, Jour> INDEX = Arrays.stream(values())
.collect(Collectors.toMap(j -> j.libelle.toLowerCase(), j -> j));
public static Jour fromLibelle(String libelle) {
Jour j = INDEX.get(libelle == null ? null : libelle.toLowerCase());
if (j == null) throw new IllegalArgumentException("Libellé inconnu : " + libelle);
return j;
}
}
Recherche en O(1) au lieu de O(n) sur un scan linéaire.
Parsing JSON
Avec Jackson, la désérialisation utilise valueOf par défaut — donc casse sensible. Pour la rendre tolérante :
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
mapper.configure(DeserializationFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true);
Ou annotez une méthode avec @JsonCreator :
public enum Statut {
ACTIF, INACTIF;
@JsonCreator
public static Statut fromJson(String s) {
return Statut.valueOf(s.toUpperCase());
}
}
values() — obtenir toutes les valeurs
for (Jour j : Jour.values()) {
System.out.println(j + " = " + j.ordinal());
}
Attention : values() crée un nouveau tableau à chaque appel. Cachez-le si vous itérez souvent.
Récapitulatif
| Besoin | Solution |
|---|---|
| Conversion stricte | Jour.valueOf("LUNDI") |
| Insensible à la casse | valueOf(s.toUpperCase()) |
| Sans exception | méthode fromString + Optional |
| Libellé différent | champ + méthode fromLibelle |
| Grand volume | cache statique en Map |
| JSON | Jackson + @JsonCreator |
La meilleure pratique : toujours exposer une méthode fromString explicite dans l'enum plutôt que de laisser les appelants composer avec valueOf et les exceptions.