Generics en Java : pourquoi en a-t-on besoin et comment les utiliser pour les débutants
Lors de l'apprentissage de Java, vous rencontrerez tôt ou tard le concept de Generics (génériques, types génériques). Pour un débutant, cela peut sembler complexe, mais c'est en réalité l'un des outils les plus utiles du langage. Dans cet article, nous allons voir ce que sont les Generics, pourquoi ils sont nécessaires et comment les utiliser correctement. Ce contenu est destiné aux développeurs débutants.
Que sont les Generics et pourquoi est-ce mauvais sans eux ?
Les Generics (types génériques) sont un mécanisme de Java qui permet de paramétrer les types. En termes simples, vous pouvez écrire une classe, une interface ou une méthode qui fonctionnera avec différents types de données, tout en conservant un typage strict à la compilation.
Imaginez que vous souhaitiez créer une boîte dans laquelle vous pouvez mettre n'importe quel objet. Sans Generics, vous devriez utiliser Object :
public class Box { private Object item;
public void put(Object item) { this.item = item; }
public Object get() { return item; }}Utiliser une telle classe est un véritable calvaire :
Box box = new Box();box.put("Hello");// Lors de l'extraction, il faut explicitement caster le typeString text = (String) box.get(); // Risque de ClassCastException !Si vous mettez accidentellement un nombre, puis essayez de le convertir en chaîne, le programme plantera avec une erreur à l'exécution. Les Generics résolvent ce problème en déplaçant la vérification des types à la compilation.
Comment utiliser les Generics : syntaxe de base
Réécrivons notre classe Box en utilisant les Generics :
public class Box<T> { private T item;
public void put(T item) { this.item = item; }
public T get() { return item; }}Ici, <T> est le paramètre de type. T est un nom conventionnel (du mot "Type"), mais vous pouvez utiliser n'importe quelle lettre ou mot : E (Element), K (Key), V (Value), etc.
Maintenant, l'utilisation est devenue sûre et élégante :
Box<String> stringBox = new Box<>();stringBox.put("Hello");String text = stringBox.get(); // Pas besoin de cast !
// Cette ligne ne compilera pas :// stringBox.put(123); // Erreur de compilation !Le compilateur sait lui-même que stringBox ne fonctionne qu'avec des chaînes. Si vous essayez de mettre un nombre, le code ne compilera même pas — vous saurez l'erreur immédiatement, et non à l'exécution.
Les Generics dans les collections : où ils sont le plus nécessaires
L'endroit le plus courant d'utilisation des Generics est les collections Java (List, Set, Map et autres). Avant l'arrivée des génériques (Java 5), les développeurs souffraient avec ArrayList, qui stockait des Object :
// Ancien style (sans Generics)List list = new ArrayList();list.add("Bonjour");list.add(123); // Cela peut aussi être ajouté !
String item = (String) list.get(0); // NormalString item2 = (String) list.get(1); // ClassCastException !Avec les Generics, tout est plus simple et plus sûr :
List<String> names = new ArrayList<>();names.add("Alice");names.add("Bob");// names.add(123); // Erreur de compilation
for (String name : names) { System.out.println(name.toUpperCase()); // Aucun cast !}La même chose fonctionne pour Map :
Map<String, Integer> ageMap = new HashMap<>();ageMap.put("Alice", 30);ageMap.put("Bob", 25);
int aliceAge = ageMap.get("Alice"); // Déballage automatique en intLimitations et wildcards : comment rendre les Generics flexibles
Parfois, vous devez limiter les types qu'un générique peut accepter. Pour cela, on utilise les paramètres de type bornés (bounded type parameters).
Par exempl