36. Interagire con l’Utente (Stream I/O Standard)
Indice
- 36.1 Gli Stream I/O Standard
- 36.2 PrintStream Cosè e Perché Esiste
- 36.3 Leggere Input come Stream I/O
- 36.4 La Classe Scanner Comoda ma Sottile
- 36.5 Chiusura degli Stream di Sistema
- 36.6 Acquisire Input con Console
- 36.7 Formattare l'Output della Console
- 36.8 Confronto tra Console Scanner e BufferedReader
- 36.9 Redirezione e Stream Standard
- 36.10 Trappole Comuni e Best Practice
- 36.11 Sintesi Finale
I programmi Java spesso devono interagire con l’utente: stampare informazioni, leggere input e formattare l’output.
Questa interazione è implementata usando gli stream I/O standard, che sono normali stream Java connessi al sistema operativo.
Questo capitolo spiega come Java interagisce con la console e l’input/output standard, partendo dai concetti più basilari e passando alle API di livello più alto.
36.1 Gli Stream I/O Standard
Ogni programma Java inizia con tre stream predefiniti forniti dalla JVM.
Sono connessi all’ambiente del processo (di solito un terminale o una console).
| Stream | Campo | Tipo | Scopo |
|---|---|---|---|
| Output standard | System.out |
PrintStream | Output normale |
| Errore standard | System.err |
PrintStream | Output di errore |
| Input standard | System.in |
InputStream | Input dell’utente |
Note
Questi stream sono creati dalla JVM, non dal programma.
Essi esistono per l’intera durata del processo.
36.2 PrintStream: Cos’è e Perché Esiste
PrintStream è uno stream di output orientato ai byte progettato per output leggibile dall’utente.
Avvolge un altro OutputStream e aggiunge metodi di stampa convenienti.
System.out e System.err sono entrambi istanze di PrintStream.
36.2.1 Caratteristiche Chiave di PrintStream
- Stream orientato ai byte con helper per la stampa di testo
- Fornisce metodi
print()eprintln() - Converte automaticamente i valori in testo
- Non lancia
IOExceptionsu errori di scrittura - Supporta opzionalmente l’auto-flush su newline /
println()
Note
A differenza della maggior parte degli stream, PrintStream sopprime le IOExceptions.
Gli errori devono essere verificati usando checkError().
36.2.2 Uso Base di PrintStream
System.out.println("Hello");
System.out.print("Value: ");
System.out.println(42);
println() aggiunge automaticamente il separatore di linea specifico della piattaforma.
36.2.3 Formattare l’Output con PrintStream
PrintStream supporta output formattato usando printf() e format(),
che sono basati sulla stessa sintassi di String.format().
System.out.printf("Name: %s, Age: %d%n", "Alice", 30);
| Specificatore | Significato |
|---|---|
%s |
Stringa |
%d |
Intero |
%f |
Virgola mobile |
%n |
Nuova linea indipendente dalla piattaforma |
Note
printf() non aggiunge automaticamente una nuova linea a meno che non si specifichi %n.
36.3 Leggere Input come Stream I/O
L’input standard (System.in) è un InputStream connesso all’input dell’utente.
Fornisce byte grezzi e deve essere adattato per un uso pratico.
36.3.1 Lettura a Basso Livello da System.in
Al livello più basso, puoi leggere byte grezzi da System.in.
Questo è raramente conveniente per programmi interattivi.
int b = System.in.read();
Note
System.in.read() si blocca finché l’input non è disponibile.
36.3.2 Uso di InputStreamReader e BufferedReader
Per leggere input testuale, System.in è tipicamente avvolto in un Reader e bufferizzato.
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine();
Questo converte byte → caratteri e permette input basato su linee.
36.4 La Classe Scanner (Comoda ma Sottile)
Scanner è un’utilità di alto livello per il parsing di input testuale.
È spesso usata per l’interazione con la console, specialmente in piccoli programmi.
Scanner sc = new Scanner(System.in);
int value = sc.nextInt();
String text = sc.nextLine();
Note
Scanner esegue tokenizzazione e parsing, non semplice lettura.
Questo la rende comoda ma più lenta e talvolta sorprendente.
36.4.1 Problemi Comuni di Scanner
- Mischiare
nextInt()(e altrinextXxx()) connextLine()può sembrare “saltare” input perché il newline finale del token numerico è ancora nel buffer. - Gli errori di parsing lanciano InputMismatchException
- Scanner è relativamente lenta per input di grandi dimensioni
36.5 Chiusura degli Stream di Sistema
Gli stream di sistema sono speciali e devono essere gestiti con attenzione.
| Stream | Chiudere esplicitamente? |
|---|---|
System.out |
No |
System.err |
No |
System.in |
Di solito no |
Chiudere System.out o System.err chiude lo stream sottostante del sistema operativo e influisce sull’intera JVM: chiudere questi stream influisce sull’intero processo JVM, non solo sulla classe o metodo corrente.
Note
In quasi tutte le applicazioni, NON dovresti chiudere System.out o System.err.
36.6 Acquisire Input con Console
La classe Console fornisce un modo di livello più alto e più sicuro per interagire con l’utente.
È progettata specificamente per programmi di console interattivi.
Console console = System.console();
if (console == null) {
throw new IllegalStateException("No console available");
}
Note
System.console() può restituire null quando nessuna console è disponibile
(ad es. IDE, input rediretto).
La presenza di una console dipende dalla piattaforma sottostante e da come viene avviata la JVM.
Se la JVM viene avviata da una riga di comando interattiva e i flussi di input/output standard non sono reindirizzati, una console è tipicamente disponibile.
In questo caso, la console è solitamente collegata alla tastiera e al display da cui è stato lanciato il programma.
Se la JVM viene avviata in un contesto non interattivo — ad esempio da un IDE, un pianificatore di processi in background, un gestore di servizi, o con flussi standard reindirizzati — di solito una console non sarà disponibile.
Quando una console esiste, è rappresentata da un’istanza unica della classe Console, che può essere ottenuta invocando il metodo System.console().
Se non è disponibile alcun dispositivo console, questo metodo restituirà null.
36.6.1 Leggere Input da Console
String name = console.readLine("Name: ");
readLine() stampa un prompt e legge una linea completa di input.
36.6.2 Leggere Password in Modo Sicuro
Console permette di leggere password senza mostrare i caratteri.
char[] password = console.readPassword("Password: ");
Note
Le password sono restituite come char[] così possono essere cancellate dalla memoria.
36.7 Formattare l’Output della Console
Console supporta anche output formattato, simile a PrintStream.
console.printf("Welcome %s%n", name);
Questo usa gli stessi specificatori di formato di printf().
36.8 Confronto tra Console, Scanner e BufferedReader
| API | Caso d’uso | Punti di forza | Limitazioni |
|---|---|---|---|
BufferedReader |
Input testuale semplice | Veloce, prevedibile, charset esplicito | Parsing manuale |
Scanner |
Input basato su token / parsing | Comoda, espressiva | Più lenta, comportamento dei token sottile |
Console |
App console interattive | Password, prompt, I/O formattato | Può non essere disponibile (null) |
36.9 Redirezione e Stream Standard
Gli stream standard possono essere rediretti dal sistema operativo. Il codice Java non deve cambiare.
java App < input.txt > output.txt
Dal punto di vista del programma, System.in e System.out si comportano ancora come normali stream.
Note
La redirezione è gestita dal sistema operativo o dalla shell. Il codice Java non deve cambiare per supportarla.
36.10 Trappole Comuni e Best Practice
- PrintStream sopprime le IOExceptions
System.console()può restituire null- Non chiudere
System.outoSystem.err - Scanner mescola parsing e lettura
- Console è preferibile per le password
- Se usi
ScannersuSystem.in, non chiudere lo Scanner se altre parti del programma devono ancora leggere daSystem.in(chiudere lo Scanner chiudeSystem.in).
36.11 Sintesi Finale
System.outeSystem.errsono PrintStream per l’outputSystem.inè uno stream di byte che deve essere adattato per il testoBufferedReadereScannersono strategie comuni di inputConsolefornisce input e output interattivo sicuro- Gli stream standard si integrano naturalmente con la redirezione del sistema operativo