Warum benötigen wir eine Instanz der Scannerklasse, um eine Eingabe auf Java zu erhalten?

10

Java ist objektorientiert, aber warum müssen wir ein Objekt aus der Scannerklasse erstellen, um Eingaben zu erhalten? Könnten next()Methoden zum Beispiel nicht einfach statisch sein?

C sieht für mich ziemlich einfach aus scanf(), wenn Sie nur verwenden , gets()oder fgets(). Ich bin mir sicher, dass es für Java-Entwickler einen Grund gibt, die Scanner-Klasse zu erstellen, aber wie ist es besser, als nur eine normale Funktion für die Arbeit zu haben?

Ich habe diesen Link gefunden , der die gleiche Frage zu stellen scheint, aber die Antworten sind nur ungefähr

"Sie müssen ein Objekt erstellen, da es nicht statisch ist" ...

Meine Vermutung ist: Da Java objektorientiert ist, haben sie beschlossen, alle Eingabemethoden in eine Klasse aufzunehmen. Sie haben keine statischen Methoden angewendet, sodass Sie alle Arten von verschiedenen Quellen (Tastatureingabe, Dateieingabe ...) in verschiedenen Objekten haben können?

Ich würde mich freuen, wenn jemand die Frage bearbeiten kann, damit sie klarer klingt!

Pablito
quelle

Antworten:

34

Die Antwort lautet "weil ein Scanner einen Status hat".

Wenn Sie sich den Code für java.util.Scanner ansehen, sehen Sie eine Reihe privater Felder wie einen Puffer und die zugehörigen Informationen, einen Matcher, ein Muster, eine Eingabequelle sowie Informationen darüber, ob die Quelle geschlossen ist oder nicht, den Typ Informationen darüber, ob das Letzte übereinstimmte, Informationen darüber, ob das Letzte eine gültige Übereinstimmung war oder nicht, der für Zahlen verwendete Radix, das Gebietsschema (Informationen darüber, ob Sie .oder ,als Tausendertrennzeichen verwenden) und ein eigener LRU-Cache für kürzlich verwendete Muster , die Informationen über die letzte Ausnahme, die aufgetreten ist, einige Informationen über das Parsen von Zahlen, einige Informationen über das Parsen von Booleschen Werten, einiges mehr Informationen über das Parsen von ganzen Zahlen ... und ich denke, das ist es auch.

Wie Sie sehen können, ist das dort ein ziemlich großer Textblock. Das ist der Zustand des Scanners. Um den Scanner zu einer statischen Klasse zu machen, müsste dieser Status an einer anderen Stelle gespeichert werden. Die C-Methode hat wirklich nicht so viel zu bieten. Du hast eine fscanf. Die DATEI behält einen Status über die Position bei, an der sie sich befindet (dies muss jedoch bei jedem Aufruf von übergeben werden fscanf). Wenn es einen Fehler, haben Sie es zu verarbeiten (und dann das Schreiben beginnen Sie Code, der aussieht wie diese ) - und das Ihnen nicht sagen , Informationen wie „Ich erwarte eine Integer, fanden aber einen String.“

Wenn man sich den theoretisch statischen Scanner ansieht - der gesamte Status wird außerhalb der Klasse beibehalten, ist er nicht in der Klasse gekapselt. Andere Codebits könnten an diesen Variablen basteln. Wenn anderer Code am Status der Klasse basteln kann, ist es sehr schwierig zu überlegen, was die Klasse in einer bestimmten Situation tun wird.

Sie könnten vielleicht so etwas schreiben ScannerState { Locale loc; ... }und Code haben, der Folgendes ergibt:

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

Dies ist jedoch viel umständlicher, als wenn der Status überhaupt in einem Scannerobjekt eingekapselt ist (und der Status nicht übergeben werden muss).

Schließlich implementiert der Scanner die Schnittstelle, Iterator<String>was bedeutet, dass man sie in Code verwenden kann, wie zum Beispiel:

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

Ohne eine Instanz der Scannerklasse abrufen zu können, wird diese Art von Struktur in einer objektorientierten Sprache umständlicher.

Gemeinschaft
quelle
1
Alles, was Sie geschrieben haben, ist absolut wahr, obwohl InputStream auch den Status hat, nicht nur den Scanner. Wenn die Eingabe von der Konsole kommt, wie in C, müssen Sie keine Parameter übergeben, um die Eingabe zu starten. Ich nehme an, es wurde so gemacht , um im Einklang mit , wie andere Ströme getan , was tut Zustand erfordern.
Neil
@Neil InputStream entspricht dem FILE*(Positionszustand) in C.
Ratschenfreak
1
Scannergeräte Iterator- nicht Iterable. Es ist unmöglich, den Scanner in einer erweiterten for-Schleife zu verwenden.
Turbanoff
@ratchetfreak Genau. Das ist es, was "state" FileInputStreams haben muss, aber es gilt nicht für Eingaben von der Konsole, da es technisch bereits geöffnet ist.
Neil
1
@turbanoff Danke, dass du mich darauf angesprochen hast. Ich habe es korrigiert.
7

kurze Antwort: Sie nicht. Sie können Benutzereingaben erhalten, ohne eine Scannerinstanz zu verwenden.
Zum Beispiel: https://docs.oracle.com/javase/tutorial/essential/io/cl.html oder
http://alvinalexander.com/blog/post/java/java-source-code-read-command-line -Eingang

jwenting
quelle
String orgName = (new BufferedReader(new InputStreamReader(System.in))).readLine();Das ist schrecklich kompliziert im Vergleich zur Verwendung von a Scannerund erstellt auch neue Instanzen von nicht einem, sondern zwei Objekten, nur um sie sofort zu verwerfen.
Philipp
2
@Philipp, 1) Es ist umständlich, aber sicherlich eine Alternative, und 2) wenn Sie die Instanzen sofort verwerfen, machen Sie etwas falsch (oder Sie müssen wirklich nur eine Zeile von der Konsole lesen).
Arturo Torres Sánchez
Sie benötigen keinen Scanner, um Eingaben zu lesen. Sie benötigen auch keinen InputStreamReader und keinen BufferedReader. Sie können mit dem "rohen" Stream bei System.in arbeiten, genau wie in C. Scanner ist einfach eine sehr komfortable Möglichkeit, diesen Stream zu nutzen.
Traubenfuchs