Leggere l'Input dalla Console in Java

Concetti Chiave
  • Utilizzare BufferedReader e InputStreamReader per leggere l'input da console in modo efficiente.
  • A partire da JDK 17, è consigliato specificare il charset quando si crea un InputStreamReader collegato a System.in.
  • Per leggere un singolo carattere, utilizzare il metodo read() di BufferedReader.
  • Per leggere una riga di testo, utilizzare il metodo readLine() di BufferedReader.
  • Gestire le eccezioni I/O in modo appropriato, specialmente in applicazioni più complesse.

Lettura dell'Input da Console

Nei primi tempi di Java, l'unico modo per effettuare l'input da console era utilizzare uno stream di byte.

Oggi, utilizzare uno stream di byte per leggere l'input da console è ancora spesso accettabile, come quando viene utilizzato nei programmi di esempio. Tuttavia, per le applicazioni commerciali, il metodo preferito per leggere l'input da console è utilizzare uno stream a caratteri. Questo rende il programma più facile da internazionalizzare e mantenere.

In Java, l'input da console si ottiene (direttamente o indirettamente) leggendo da System.in. Un modo per ottenere uno stream a caratteri che è collegato alla console è incapsulare System.in in un BufferedReader. La classe BufferedReader supporta uno stream di input bufferizzato. Un costruttore comunemente utilizzato è mostrato qui:

BufferedReader(Reader input)

Qui, input è lo stream che è collegato all'istanza di BufferedReader che viene creata. Reader è una classe astratta. Una delle sue sottoclassi concrete è InputStreamReader, che converte i byte in caratteri.

A partire da JDK 17, il modo preciso in cui si ottiene un InputStreamReader collegato a System.in è cambiato.

In passato, era comune utilizzare il seguente costruttore InputStreamReader per questo scopo:

InputStreamReader(InputStream stream)

Poiché System.in si riferisce a un oggetto di tipo InputStream, può essere utilizzato per stream. Quindi, in passato, la seguente riga di codice mostra un approccio comunemente utilizzato per creare un BufferedReader collegato alla tastiera:

BufferedReader br =
    new BufferedReader(new InputStreamReader(System.in));

Dopo l'esecuzione di questa istruzione, br è uno stream a caratteri che è collegato alla console attraverso System.in.

Tuttavia, a partire da JDK 17, ora è raccomandato specificare esplicitamente il charset associato alla console quando si crea l'InputStreamReader. Un charset definisce il modo in cui i byte vengono mappati ai caratteri. Normalmente, quando un charset non è specificato, viene utilizzato il charset predefinito della JVM. Tuttavia, nel caso della console, il charset utilizzato per l'input da console può differire da questo charset predefinito. Quindi, ora è raccomandato che questa forma del costruttore di InputStreamReader venga utilizzata:

InputStreamReader(InputStream stream, Charset charset)

Per charset, si può utilizzare il charset associato alla console. Questo charset è restituito da charset(), che è un nuovo metodo aggiunto da JDK 17 alla classe Console. Si ottiene un oggetto Console chiamando System.console(). Restituisce un riferimento alla console, o null se non è presente alcuna console. Pertanto, oggi la seguente sequenza mostra un modo per incapsulare System.in in un BufferedReader:

// Ottiene la Console
Console con = System.console();

if (con == null) {
    // Il Sistema non ha una console
    return;
}

BufferedReader br = new
    BufferedReader(new InputStreamReader(System.in, con.charset()));

Naturalmente, nei casi in cui si sa che una console sarà presente, la sequenza può essere accorciata a:

BufferedReader br =
    new BufferedReader(
        new InputStreamReader(System.in,
                              System.console().charset()));

Un altro punto da tener presente: È anche possibile ottenere un Reader che è già associato alla console utilizzando il metodo reader() definito da Console. Tuttavia, utilizzeremo l'approccio InputStreamReader come appena descritto perché dimostra esplicitamente il modo in cui i byte stream e i character stream possono interagire.

Lettura di Caratteri

Per leggere un carattere da un BufferedReader, utilizziamo read().

La versione di read() che utilizzeremo è

int read() throws IOException

Ogni volta che viene chiamato, read() legge un carattere dal flusso di input e lo restituisce come valore intero. Restituisce –1 quando viene fatto un tentativo di lettura alla fine del flusso. Come possiamo vedere, può lanciare un IOException.

Il seguente programma dimostra read() leggendo caratteri dalla console finché l'utente non digita una "q". Notiamo che qualsiasi eccezione I/O che potrebbe essere generata viene semplicemente lanciata fuori da main(). Tale approccio è comune quando si legge dalla console in semplici programmi di esempio come quelli mostrati in queste lezioni, ma in applicazioni più sofisticate, possiamo gestire le eccezioni esplicitamente.

// Utilizziamo un BufferedReader per leggere caratteri dalla console.
import java.io.*;

class BRLeggi {

    public static void main(String[] args) throws IOException {
        char c;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, System.console().charset()));
        System.out.println("Inserisci caratteri, 'q' per uscire.");
        // leggiamo caratteri

        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != 'q');
    }

}

Ecco un esempio di esecuzione:

Inserisci caratteri, 'q' per uscire.
ciao
c
i
a
o


Come si va?
C
o
m
e

s
i

v
a
?


q
q

Questo output potrebbe apparire un po' diverso da quello che ci aspettavamo perché System.in è bufferizzato per linea, per default. Questo significa che nessun input viene effettivamente passato al programma finché non premiamo invio. Come possiamo immaginare, questo non rende read() particolarmente utile per l'input interattivo dalla console.

Leggere Stringhe

Per leggere una stringa dalla tastiera, utilizziamo la versione di readLine() che è un membro della classe BufferedReader. La sua forma generale è mostrata qui:

String readLine() throws IOException

Come possiamo vedere, restituisce un oggetto String.

Il seguente programma dimostra BufferedReader e il metodo readLine(); il programma legge e visualizza righe di testo finché non inseriamo la parola "stop":

// Legge una stringa dalla console usando un BufferedReader.

import java.io.*;

class BRLeggiRighe {

    public static void main(String[] args) throws IOException {

        // crea un BufferedReader usando System.in
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, System.console().charset()));
        String str;
        System.out.println("Inserisci righe di testo.");
        System.out.println("Inserisci 'stop' per uscire.");
        do {
            str = br.readLine();
            System.out.println(str);
        } while (!str.equals("stop"));
    }

}

Un possibile output di questo programma è:

Inserisci righe di testo.
Inserisci 'stop' per uscire.
Ciao
Ciao
Come stai?
Come stai?
stop
stop

L'esempio successivo crea un piccolo editor di testo. Crea un array di oggetti String e poi legge righe di testo, memorizzando ogni riga nell'array. Leggerà fino a 100 righe o finché non inseriamo "stop". Usa un BufferedReader per leggere dalla console.

// Un piccolo editor.
import java.io.*;

class PiccoloEditor {

    public static void main(String[] args) throws IOException {
        // crea un BufferedReader usando System.in
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, System.console().charset()));
        String[] str = new String[100];
        System.out.println("Inserisci righe di testo.");
        System.out.println("Inserisci 'stop' per uscire.");
        for (int i = 0; i < 100; i++) {
            str[i] = br.readLine();
            if (str[i].equals("stop"))
                break;
        }
        System.out.println("\nEcco il tuo file:");
        // visualizza le righe
        for (int i = 0; i < 100; i++) {
            if (str[i].equals("stop"))
                break;
            System.out.println(str[i]);
        }
    }

}

Ecco un esempio di esecuzione:

Inserisci righe di testo.
Inserisci 'stop' per uscire.
Ciao, come stai?
Tutto bene?
Oggi è una bella giornata
stop

Ecco il tuo file:
Ciao, come stai?
Tutto bene?
Oggi è una bella giornata