Perché è necessaria un'istanza della classe Scanner per ottenere un input su Java?


10

Java è orientato agli oggetti, ma perché è necessario creare un oggetto dalla classe Scanner per ottenere l'input? I next()metodi, ad esempio, non potrebbero essere statici?

C a me sembra abbastanza semplice, come si basta usare scanf(), gets()o fgets(). Sono sicuro che c'è una ragione per gli sviluppatori Java per creare la classe Scanner, ma come è meglio che avere una normale funzione per fare il lavoro?

Ho trovato questo link che potrebbe sembrare porre la stessa domanda, ma le risposte sono quasi

"devi creare un oggetto perché non è statico" ...

La mia ipotesi è: dal momento che Java è orientato agli oggetti, hanno deciso di mettere tutti i metodi di input in una classe. Non hanno fatto metodi statici, quindi puoi avere tutti i tipi di fonti diverse (input da tastiera, input file ...) in oggetti diversi?

Gradirei se qualcuno potesse modificare la domanda per renderla più chiara!

Risposte:


34

La risposta è "perché uno scanner ha stato".

Guardando il codice per java.util.Scanner , vedrai un numero di campi privati ​​come un buffer e le informazioni ad esso associate, un Matcher, un Pattern, una sorgente di input, informazioni su se la sorgente è chiusa o meno, il tipo dell'ultima cosa abbinata, informazioni su se l'ultima cosa fosse una corrispondenza valida o meno, la radice utilizzata per i numeri, le impostazioni locali (informazioni su se si sta utilizzando .o ,come separatore delle migliaia) e la propria cache LRU per i modelli utilizzati di recente , le informazioni sull'ultima eccezione riscontrata, alcune informazioni sull'analisi dei numeri, alcune informazioni sull'analisi dei valori booleani, un po 'più informazioni sull'analisi dei numeri interi ... e penso che sia tutto qui.

Come puoi vedere, questo è un blocco di testo abbastanza grande lì. Questo è lo stato dello scanner. Al fine di trasformare lo scanner in una classe statica, tale stato dovrebbe essere memorizzato altrove. Il modo in cui lo fa in realtà non ha molto stato con esso. Hai un fscanf. Il FILE mantiene un certo stato sulla posizione in cui si trova (ma che deve essere passato per ogni invocazione di fscanf). Se si è verificato un errore, devi elaborarlo (e quindi inizi a scrivere codice simile a questo ) - e questo non ti dice informazioni come "Mi aspettavo un numero intero, ma ho trovato una stringa".

Quando si guarda allo scanner teoricamente statico, tutto lo stato viene mantenuto al di fuori della classe, non è incapsulato all'interno della classe. Altri bit di codice potrebbero armeggiare con quelle variabili. Quando un altro codice può armeggiare con lo stato della classe, diventa molto difficile ragionare su cosa farà la classe in una determinata situazione.

Potresti, forse, scrivere qualcosa di simile ScannerState { Locale loc; ... }e avere un codice che risulta in:

ScannerState state = new ScannerState(a whole lot of arguments);
int foo = Scanner.nextInt(state);

Ma poi, questo è molto più ingombrante che avere lo stato incapsulato in un oggetto Scanner in primo luogo (e non è necessario passare nello stato).

Infine, lo scanner implementa l'interfaccia il Iterator<String>che significa che è possibile utilizzarlo in codice come:

Scanner in = new Scanner(someFile);
whie(in.hasNext()) { ... }

Senza essere in grado di ottenere un'istanza della classe Scanner, questo tipo di struttura diventa più ingombrante all'interno di un linguaggio orientato agli oggetti.


1
Tutto ciò che hai scritto è assolutamente vero, anche se InputStream ha anche lo stato, non solo Scanner. Se l'input proviene dalla console, come in C, non è necessario passare alcun parametro per iniziare a ricevere l'input. Suppongo che è stato fatto in questo modo per essere coerenti con il modo in altri corsi d'acqua sono fatti che non richiedono lo stato.
Neil,

@Neil InputStream equivale allo FILE*(stato di posizione) in C.
maniaco del cricchetto

1
Strumenti dello scanner Iterator- no Iterable. È impossibile utilizzare Scanner nel ciclo avanzato.
Turbanoff,

@ratchetfreak Precisely. Questo è ciò che deve avere "state" FileInputStreams, ma non si applica all'input dalla console poiché è già tecnicamente aperto.
Neil,

1
@turbanoff Grazie per avermi chiamato. L'ho corretto.

7

risposta breve: non lo fai. È possibile ottenere l'input dell'utente senza utilizzare un'istanza Scanner.
Ad esempio: https://docs.oracle.com/javase/tutorial/essential/io/cl.html o
http://alvinalexander.com/blog/post/java/java-source-code-read-command-line -ingresso


String orgName = (new BufferedReader(new InputStreamReader(System.in))).readLine();Questo è orribilmente contorto rispetto all'uso di a Scannere crea anche nuove istanze di non uno ma due oggetti solo per scartarli immediatamente.
Philipp,

2
@Philipp, 1) È ingombrante, ma è certamente un'alternativa, e 2) se scarti subito le istanze stai facendo qualcosa di sbagliato (o hai davvero bisogno di leggere solo una riga dalla console).
Arturo Torres Sánchez,

Non è necessario scanner per leggere l'input. Inoltre, non è necessario un InputStreamReader e non è necessario un BufferedReader. Puoi lavorare con il flusso "raw" su System.in, proprio come in C. Scanner è semplicemente un modo molto comodo per consumare quel flusso.
Traubenfuchs,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.