0Pricing
Java Academy · Leçon

Jokers dans les API

Concevez des méthodes génériques flexibles

Jokers dans les API est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.

Concevoir des méthodes flexibles

Les caractères génériques sont principalement un outil pour les concepteurs d’API. Un caractère générique bien placé permet aux appelants de transmettre davantage de types sans conversions.

Objectif : une souplesse maximale pour les appelants et une sécurité totale des types à l’intérieur.

import java.util.List;

public class Main {
    static double total(List<? extends Number> items) {
        double sum = 0;
        for (Number n : items) sum += n.doubleValue();
        return sum;
    }
    public static void main(String[] args) {
        System.out.println(total(List.of(1, 2, 3)));
        System.out.println(total(List.of(1.5, 2.5)));
    }
}

Caractères génériques non bornés

List<?> est un caractère générique non borné : une liste dont le type est inconnu.

Utilisez-le lorsque votre méthode ne se soucie pas du type des éléments, par exemple pour compter les éléments ou vérifier si la liste est vide.

import java.util.List;

public class Main {
    static int size(List<?> any) {
        return any.size();
    }
    public static void main(String[] args) {
        System.out.println(size(List.of("a", "b")));
        System.out.println(size(List.of(1, 2, 3)));
    }
}

List<?> et List<Object>

Ces deux types sont différents. List<Object> n’accepte qu’une liste déclarée avec Object. List<?> accepte une liste de n’importe quel type.

Vous pouvez transmettre une List<String> à un paramètre List<?>, mais pas à un paramètre List<Object>.

import java.util.List;

public class Main {
    static void printAll(List<?> list) {
        for (Object o : list) System.out.println(o);
    }
    public static void main(String[] args) {
        List<String> names = List.of("Ada", "Linus");
        printAll(names); // works; List<Object> would reject this
    }
}

Quand un paramètre de type est plus clair

Si vous devez faire référence au type des éléments plusieurs fois, un paramètre de type nommé est plus lisible qu’un caractère générique.

Comparez void swap(List<?> l, int i, int j) (qui nécessite un assistant privé) avec une version générique claire.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void swap(List<T> list, int i, int j) {
        T tmp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, tmp);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("a", "b", "c"));
        swap(list, 0, 2);
        System.out.println(list);
    }
}

L’astuce de capture avec un assistant

Si une API publique doit utiliser List<?>, vous pouvez déléguer le travail à un assistant générique privé afin de capturer le caractère générique.

L’assistant nomme le type T, ce qui lui permet de réécrire dans la liste.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void reverse(List<?> list) { reverseHelper(list); }
    private static <T> void reverseHelper(List<T> list) {
        for (int i = 0, j = list.size() - 1; i < j; i++, j--) {
            T tmp = list.get(i);
            list.set(i, list.get(j));
            list.set(j, tmp);
        }
    }
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4));
        reverse(list);
        System.out.println(list);
    }
}

Paramètres producteurs dans une véritable API

Concevoir une opération addAll qui récupère des éléments depuis n’importe quelle source compatible nécessite une borne supérieure sur la source.

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Main {
    static <T> void addAll(List<T> target, Collection<? extends T> source) {
        for (T t : source) target.add(t);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addAll(nums, List.of(1, 2, 3));
        System.out.println(nums);
    }
}

Paramètres consommateurs dans une véritable API

Une API de destination qui écrit les résultats utilise une borne inférieure sur la destination, afin que les appelants puissent fournir des conteneurs plus généraux.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void repeat(T value, int times, List<? super T> sink) {
        for (int i = 0; i < times; i++) sink.add(value);
    }
    public static void main(String[] args) {
        List<Object> out = new ArrayList<>();
        repeat("hi", 3, out);
        System.out.println(out);
    }
}

Caractères génériques avec des types génériques imbriqués

Les types génériques imbriqués ont souvent besoin de caractères génériques. Une méthode qui accepte une liste contenant n’importe quel type de liste utilise List<? extends List<?>>.

import java.util.List;

public class Main {
    static int countAll(List<? extends List<?>> lists) {
        int total = 0;
        for (List<?> inner : lists) total += inner.size();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(countAll(List.of(List.of(1, 2), List.of("a", "b", "c"))));
    }
}

Éviter la généralisation excessive

Toutes les méthodes n’ont pas besoin de caractères génériques. Si les appelants ne transmettent toujours qu’un seul type, un paramètre ordinaire est plus clair.

Ajoutez des caractères génériques lorsque vous constatez que de véritables appelants sont bloqués par l’invariance, et non par anticipation.

import java.util.List;

public class Main {
    // Simple and clear; no wildcard needed for this internal use
    static String joinStrings(List<String> parts) {
        return String.join(", ", parts);
    }
    public static void main(String[] args) {
        System.out.println(joinStrings(List.of("a", "b", "c")));
    }
}

Documenter l’intention d’un caractère générique

Un caractère générique exprime une intention. ? extends T indique aux lecteurs « je ne fais que lire ceci ». ? super T signifie « je ne fais qu’écrire ceci ».

Choisir le bon caractère générique revient à écrire du code qui se documente lui-même, tout en faisant respecter le contrat.

import java.util.ArrayList;
import java.util.List;

public class Main {
    // src: read-only producer; dest: write-only consumer
    static <T> void transfer(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Number> dest = new ArrayList<>();
        transfer(List.of(1, 2), dest);
        System.out.println(dest);
    }
}

Une API Stack générique

L’exemple célèbre de Stack présenté par Bloch : pushAll consomme depuis un producteur (borne supérieure), tandis que popAll produit vers un consommateur (borne inférieure).

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.ArrayList;
import java.util.List;

public class Main {
    static class Stack<E> {
        private final Deque<E> items = new ArrayDeque<>();
        void pushAll(Collection<? extends E> src) { for (E e : src) items.push(e); }
        void popAll(Collection<? super E> dst) { while (!items.isEmpty()) dst.add(items.pop()); }
    }
    public static void main(String[] args) {
        Stack<Integer> s = new Stack<>();
        s.pushAll(List.of(1, 2, 3));
        List<Number> out = new ArrayList<>();
        s.popAll(out);
        System.out.println(out);
    }
}

Vérification rapide

Testez votre intuition en matière de conception d’API.

Récapitulatif

Vous avez appris à concevoir des API avec des caractères génériques :

  • List<?> pour les méthodes en lecture seule qui ne dépendent pas du type.
  • Appliquez PECS aux paramètres pour gagner en souplesse.
  • Utilisez l’astuce de capture avec un assistant privé lorsque vous devez écrire au moyen d’un caractère générique.
  • Évitez les caractères génériques dans les types de retour et n’en utilisez pas à outrance.

Vous avez terminé le cours sur les caractères génériques et PECS.

public class Main {
    public static void main(String[] args) {
        System.out.println("Wildcards in APIs course complete");
    }
}

Questions Fréquemment Posées

La leçon « Jokers dans les API » est-elle gratuite ?

Oui — le texte complet de « Jokers dans les API » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Jokers dans les API » ?

Concevez des méthodes génériques flexibles Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Java Academy ?

Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Jokers dans les API » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?

Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Jokers à borne supérieure
  2. Jokers à borne inférieure
  3. Principe PECS
  4. Jokers dans les API
← Retour à Java Academy