Metodi Varargs in Java

Concetti Chiave
  • I metodi varargs in Java consentono di passare un numero variabile di argomenti a un metodo, semplificando la gestione degli argomenti.
  • La sintassi int ... v indica che il metodo può accettare zero o più argomenti di tipo int, che vengono trattati come un array all'interno del metodo.
  • I metodi varargs possono essere combinati con parametri normali, ma il parametro varargs deve essere l'ultimo nella dichiarazione del metodo.
  • I metodi varargs sono utili in situazioni in cui si desidera passare un numero variabile di argomenti, come nel caso di metodi che gestiscono connessioni o formattazione di output.

Varargs: Argomenti a Lunghezza Variabile

Le versioni moderne di Java includono una funzionalità che semplifica la creazione di metodi che devono accettare un numero variabile di argomenti.

Questa funzionalità è chiamata varargs ed è l'abbreviazione di variable-length arguments. Un metodo che accetta un numero variabile di argomenti è chiamato metodo a arità variabile, o semplicemente metodo varargs.

Situazioni che richiedono che un numero variabile di argomenti venga passato a un metodo non sono insolite.

Per esempio, un metodo che apre una connessione Internet potrebbe richiedere un nome utente, una password, un nome di file, un protocollo, e così via, ma fornire dei valori predefiniti se alcune di queste informazioni non vengono specificate.

In questa situazione, sarebbe comodo passare solo gli argomenti a cui i valori predefiniti non si applicano. Un altro esempio è il metodo printf() che fa parte della libreria I/O di Java. Come si vedrà nelle prossime lezioni, esso accetta un numero variabile di argomenti, che formatta e poi stampa.

Nei primi tempi di Java, gli argomenti a lunghezza variabile potevano essere gestiti in due modi, nessuno dei quali particolarmente soddisfacente:

Primo, se il numero massimo di argomenti era piccolo e noto, si potevano creare versioni sovraccaricate del metodo, una per ciascun modo in cui il metodo poteva essere chiamato. Sebbene ciò funzioni ed è adatto per alcuni casi, si applica solo a una classe ristretta di situazioni.

Nei casi in cui il numero massimo di argomenti potenziali era maggiore o sconosciuto, si usava un secondo approccio in cui gli argomenti venivano inseriti in un array, e poi l'array veniva passato al metodo. Questo approccio, che si può ancora trovare in vecchio codice legacy, è illustrato dal seguente programma:

// Usare un array per passare un numero variabile di
// argomenti a un metodo. Questo è il metodo vecchio stile
// per gestire gli argomenti a lunghezza variabile.
class PassaArray {
    static void provaArray(int[] v) {
        System.out.print("Numero di argomenti: " + v.length +
                         " Contenuti: ");

        for(int x : v)
            System.out.print(x + " ");
        System.out.println();
    }

    public static void main(String[] args)
    {
        // Notare come debba essere creato un array per
        // contenere gli argomenti.
        int[] n1 = { 10 };
        int[] n2 = { 1, 2, 3 };
        int[] n3 = { };

        provaArray(n1); // 1 argomento
        provaArray(n2); // 3 argomenti
        provaArray(n3); // nessun argomento
    }
}

L'output del programma è mostrato qui:

Numero di argomenti: 1 Contenuti: 10
Numero di argomenti: 3 Contenuti: 1 2 3
Numero di argomenti: 0 Contenuti:

Nel programma, il metodo provaArray() riceve i suoi argomenti attraverso l'array v. Questo vecchio approccio per gestire gli argomenti a lunghezza variabile permette a provaArray() di accettare un numero arbitrario di argomenti. Tuttavia, richiede che questi argomenti vengano manualmente inseriti in un array prima di chiamare provaArray(). Non solo è tedioso costruire un array ogni volta che si chiama provaArray(), ma è potenzialmente soggetto a errori. La funzionalità varargs offre un'opzione più semplice e migliore.

Varargs: Un Nuovo Approccio

Un argomento a lunghezza variabile è specificato da tre punti (...). Per esempio, ecco come provaVarargs() è scritto usando un vararg:

static void provaVarargs(int ... v) {

Questa sintassi dice al compilatore che provaVarargs() può essere chiamato con zero o più argomenti. Di conseguenza, v è implicitamente dichiarato come un array di tipo int[]. Quindi, all'interno di provaVarargs(), v viene gestito usando la normale sintassi array. Ecco il programma precedente riscritto usando un vararg:

// Dimostrare gli argomenti a lunghezza variabile.
class VarArgs {

    // provaVarargs() ora usa un vararg.
    static void provaVarargs(int ... v) {
        System.out.print("Numero di argomenti: " + v.length +
                         " Contenuti: ");

        for(int x : v)
            System.out.print(x + " ");

        System.out.println();
    }

    public static void main(String[] args)
    {
        // Notare come provaVarargs() possa essere chiamato con
        // un numero variabile di argomenti.
        provaVarargs(10);         // 1 argomento
        provaVarargs(1, 2, 3);    // 3 argomenti
        provaVarargs();           // nessun argomento
    }
}

L'output del programma è lo stesso della versione originale.

Ci sono due cose importanti da notare su questo programma. Primo, come spiegato, all'interno di provaVarargs(), v è gestito come un array. Questo perché v è un array. La sintassi ... indica semplicemente al compilatore che sarà usato un numero variabile di argomenti, e che questi argomenti verranno memorizzati in un array a cui si accede tramite v. Secondo, in main(), provaVarargs() è chiamato con un numero variabile di argomenti. Gli argomenti vengono automaticamente impacchettati in un array. In altre parole, l'array viene creato automaticamente dal compilatore.

Combinare Varargs con Parametri Normali

Un metodo può avere parametri normali insieme a un parametro a lunghezza variabile. Tuttavia, il parametro a lunghezza variabile deve essere l'ultimo parametro dichiarato dal metodo. Per esempio, la seguente dichiarazione di metodo è perfettamente accettabile:

int esegui(int a, int b, double c, int ... valori) {

In questo caso, i primi tre argomenti usati in una chiamata a esegui() sono associati ai primi tre parametri. Poi, tutti gli argomenti rimanenti si presume appartengano a valori.

Bisogna ricordare che il parametro varargs deve essere l'ultimo. Per esempio, la seguente dichiarazione è errata:

int esegui(int a, int b, double c, int ... valori, boolean flagStop) { // Errore!

Qui si sta tentando di dichiarare un parametro normale dopo il parametro varargs, il che non è consentito.

C'è un'altra restrizione da tenere a mente: ci deve essere un solo parametro varargs. Per esempio, anche questa dichiarazione non è valida:

int esegui(int a, int b, double c, int ... valori, double ... altriValori) { // Errore!

Il tentativo di dichiarare un secondo parametro varargs non è consentito.

Ecco una versione rielaborata del metodo provaVarargs() che accetta un argomento regolare e un argomento a lunghezza variabile:

// Usare varargs con argomenti standard.
class VarArgs2 {

    // Qui, msg è un parametro normale e v è un
    // parametro varargs.
    static void provaVarargs(String msg, int ... v) {
        System.out.print(msg + v.length +
                         " Contenuti: ");

        for(int x : v)
            System.out.print(x + " ");

        System.out.println();
    }

    public static void main(String[] args)
    {
        provaVarargs("Un vararg: ", 10);
        provaVarargs("Tre varargs: ", 1, 2, 3);
        provaVarargs("Nessun vararg: ");
    }
}

L'output di questo programma è mostrato qui:

Un vararg: 1 Contenuti: 10
Tre varargs: 3 Contenuti: 1 2 3
Nessun vararg: 0 Contenuti: