0Pricing
Java Academy · Lezione

Wildcard nelle API

Progettare metodi generici flessibili

Wildcard nelle API è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

Progettare metodi flessibili

Le wildcard sono soprattutto uno strumento per i progettisti di API. Una wildcard collocata correttamente consente a chi chiama il metodo di passare più tipi senza effettuare cast.

L'obiettivo è offrire la massima flessibilità a chi chiama il metodo, mantenendo la completa sicurezza dei tipi al suo interno.

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)));
    }
}

Wildcard non limitate

List<?> è una wildcard non limitata: una lista di un tipo sconosciuto.

La utilizzi quando il metodo non ha bisogno di conoscere il tipo degli elementi, ad esempio per contarli o verificare se la lista è vuota.

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<?> e List<Object> a confronto

Sono tipi diversi. List<Object> accetta solo una lista dichiarata come Object. List<?> accetta una lista di qualsiasi tipo.

È possibile passare una List<String> a un parametro List<?>, ma non a un parametro 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
    }
}

Quando un parametro di tipo è più chiaro

Se deve fare riferimento al tipo degli elementi più di una volta, un parametro di tipo con nome è più leggibile di una wildcard.

Confronti void swap(List<?> l, int i, int j) (che richiede un helper privato) con una versione generica più chiara.

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);
    }
}

La tecnica di cattura tramite helper

Se un'API pubblica deve usare List<?>, può delegare a un helper generico privato per catturare la wildcard.

L'helper assegna un nome al tipo T, così può riscrivere gli elementi nella lista.

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);
    }
}

Parametri produttori in un'API reale

Progettare un'operazione addAll che acquisisca dati da qualsiasi sorgente compatibile richiede un limite superiore sulla sorgente.

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);
    }
}

Parametri consumatori in un'API reale

Un'API di destinazione che scrive i risultati usa un limite inferiore sulla destinazione, così chi la chiama può fornire contenitori più generali.

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);
    }
}

Wildcard con generics annidati

I generics annidati spesso richiedono wildcard. Un metodo che accetta una lista contenente qualsiasi tipo di lista usa 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"))));
    }
}

Evitare l'uso eccessivo dei generics

Non tutti i metodi hanno bisogno di wildcard. Se chi chiama il metodo passa sempre un solo tipo, un parametro semplice è più chiaro.

Aggiunga le wildcard quando osserva che l'invarianza impedisce realmente l'uso da parte dei chiamanti, non in via preventiva.

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")));
    }
}

Documentare l'intento delle wildcard

Una wildcard comunica un'intenzione. ? extends T dice ai lettori "Leggo soltanto da qui". ? super T indica "Scrivo soltanto qui".

Scegliere la wildcard corretta è una forma di codice autoesplicativo che, inoltre, applica il contratto.

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);
    }
}

Un'API per uno stack generico

Il famoso esempio di stack di Bloch: pushAll consuma da un produttore (extends), mentre popAll produce verso un consumatore (super).

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);
    }
}

Verifica rapida

Verifichi la Sua capacità di progettare API.

Riepilogo

Ha imparato a progettare API con le wildcard:

  • List<?> per i metodi di sola lettura indipendenti dal tipo.
  • Applichi PECS ai parametri per aumentare la flessibilità.
  • Utilizzi la tecnica privata di cattura tramite helper quando deve scrivere attraverso una wildcard.
  • Eviti le wildcard nei tipi restituiti e non utilizzi i generics in modo eccessivo.

Ha completato il corso sulle wildcard e su PECS.

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

Domande Frequenti

La lezione «Wildcard nelle API» è gratuita?

Sì — il testo completo di «Wildcard nelle API» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «Wildcard nelle API»?

Progettare metodi generici flessibili Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Wildcard nelle API»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Wildcard con limite superiore
  2. Wildcard con limite inferiore
  3. Il principio PECS
  4. Wildcard nelle API
← Torna a Java Academy