Exception: es dürfen nur Nummern eingelesen werden

LiFunk

Neues Mitglied
Hallo,

ich möchte eine Eingabe programmieren, die nur Zahlen zulässt, das habe ich mit einer Exception realisiert.
Java:
        while(test==true) {
        try {
                test=false;
                System.out.println("Erste Zahl eingeben:");
                a = scan.nextInt();
            }
        catch(InputMismatchException  e) {
                System.out.println("FEHLER: Falsche Eingabe");
                test=true;
            }
        
        }
Wenn eine Zahl eingegeben wird, funktioniert das Verlassen der Schleife. Wenn allerdings keine Zahl eingegeben wird, geht es in catch rein und gibt den Text aus. Dann fragt es wieder nach einer Zahl, hält allerdings nicht an um eine Eingabe zu ermöglichen, sondern läuft jetzt immer weiter im Kreis, also:
FEHLER: ...
Erste Zahl ...
FEHLER: ....
....
Wie lass ich das Programm anhalten um eine Eingabe zu ermöglichen?

Vielen Dank im Vorraus
LiFunk
 
Führe im Fehlerfall das hier aus:
[CODE lang="java" title="Next"]scan.next();[/CODE]

Musste selbst erst probieren, ich war der Meinung mit reset() wäre es erledigt, aber man muss genau anders rum dem Scanner sagen, dass er das, was sich schon drin befindet, ignorieren soll.
 
Erst einmal das Verhalten erklärt:

Der Scanner liest aus dem System.in Stream mit den meisten Methoden immer Token für Token aus. Dabei ist der Stream so aufgebaut, dass eine Eingabe immer erst mit der Entertaste gelesen werden kann.

Wenn Du nun etwas wie nextInt aufrufst, dann schaut er nach, ob im Puffer eine Zahl steht. Wenn dies der Fall ist, wird die Zahl gelesen und dann zurück gegeben. Wenn da keine Zahl drin steht, wird auch nichts aus dem Puffer gelesen. Die Zeichen bleiben also weiter im Stream enthalten und jeder folgende Aufruf scheitert erneut.

Daher musst du die illegalen Zeichen aus dem Stream entfernen. Dazu bietet sich nextLine an, denn dies liest die ganze Eingabe bis zum Return ein.

Führe im Fehlerfall das hier aus:
[CODE lang="java" title="Next"]scan.next();[/CODE]

Musste selbst erst probieren, ich war der Meinung mit reset() wäre es erledigt, aber man muss genau anders rum dem Scanner sagen, dass er das, was sich schon drin befindet, ignorieren soll.
Nein, das ist nicht ausreichend. In dem eingegebenen Text können mehrere Token enthalten sein, also wenn z.B. "hallo du" eingegeben wird, dann würde next nur das nächste Token (hallo) auslesen. Daher ist nextLine der korrekte Weg, die Eingabe komplett zu lesen.
 
Erst einmal das Verhalten erklärt:

Der Scanner liest aus dem System.in Stream mit den meisten Methoden immer Token für Token aus. Dabei ist der Stream so aufgebaut, dass eine Eingabe immer erst mit der Entertaste gelesen werden kann.

Wenn Du nun etwas wie nextInt aufrufst, dann schaut er nach, ob im Puffer eine Zahl steht. Wenn dies der Fall ist, wird die Zahl gelesen und dann zurück gegeben. Wenn da keine Zahl drin steht, wird auch nichts aus dem Puffer gelesen. Die Zeichen bleiben also weiter im Stream enthalten und jeder folgende Aufruf scheitert erneut.

Daher musst du die illegalen Zeichen aus dem Stream entfernen. Dazu bietet sich nextLine an, denn dies liest die ganze Eingabe bis zum Return ein.


Nein, das ist nicht ausreichend. In dem eingegebenen Text können mehrere Token enthalten sein, also wenn z.B. "hallo du" eingegeben wird, dann würde next nur das nächste Token (hallo) auslesen. Daher ist nextLine der korrekte Weg, die Eingabe komplett zu lesen.
Dann machen wir noch Nägel mit Köpfen und fügen vor der Eingabeaufforderung eine while(scan.hasNext()) Abfrage ein, um auch jede Texteingabe zu ignorieren, die während des Programmstarts oder der Fehlerbehandlung (kann ja sein) gemacht wurde.
Edit: Lieber doch nicht 😀 Mir ist gerade mein Irrweg klargeworden.
 
Evtl. auch noch der Hinweis: Wenn man möchte, dann kann man das Einlesen eines Token auch generell mit dem "Löschen" weiterer Eingaben verbinden. Das wäre dann Code, der so in der Art aussehen könnte (Stark gekürzt):
Java:
            try {
                scanner.nextInt();
            }
            catch(InputMismatchException e) {
                // ...
            } finally {
                scanner.nextLine();
            }

Das nimmt einem Anwender aber die Möglichkeit, mehrere Dinge sofort einzugeben. Also nehmen wir einfach einmal folgenden Code:
Java:
        Scanner scanner = new Scanner(System.in);
        System.out.print("1. Zahl: ");
        scanner.nextInt();
        System.out.print("2. Zahl: ");
        scanner.nextInt();

Es werden zwei Zahlen abgefragt. Wenn man aber weiss, dass zwei Zahlen abgefragt werden, dann kann man direkt schreiben: "1 2"
Das erste nextInt nimmt die 1 und das zweite nextInt nimmt sich die 2.

So etwas würde durch jede Bereinigung nach dem einlesen eines Token nicht mehr möglich sein. Wenn man den Inhalt des nextLine auswertet, dann könnte man sogar dem Nutzer noch sagen, dass nur die erste Zahl genommen wurde und die 2 verworfen wurde... Man kann da also noch einiges bauen.

Dann machen wir noch Nägel mit Köpfen und fügen vor der Eingabeaufforderung eine while(scan.hasNext()) Abfrage ein, um auch jede Texteingabe zu ignorieren, die während des Programmstarts oder der Fehlerbehandlung (kann ja sein) gemacht wurde.
Das wäre bei einem Programmstart durchaus interessant - würde aber jede Chance nehmen, ein Programm automatisiert laufen zu lassen. Also auf der Shell z.B. einen Aufruf a.la.
java Test < eingabe.txt
 
Das wäre bei einem Programmstart durchaus interessant - würde aber jede Chance nehmen, ein Programm automatisiert laufen zu lassen. Also auf der Shell z.B. einen Aufruf a.la.
java Test < eingabe.txt
Und es klappt eh nicht. Mir ist gerade aufgefallen, dass der Befehl nicht ganz das macht, was ich erwartet habe.
Ehrlich gesagt gefällt mir der Gedanke auch recht unsympatische ein User-TextInterface automatisch befüllen zu lassen. Da ist mir die Vorstellung lieber, erst mal die Eingabe zu prüfen und das Interface nur zustarten, wenn nichts da ist.
 
Und es klappt eh nicht. Mir ist gerade aufgefallen, dass der Befehl nicht ganz das macht, was ich erwartet habe.
Ja stimmt, hasNext() wartet auch auf die nächste Eingabe wenn notwendig. Daher kann so eine Schleife nicht wirklich etwas bringen.

So lange es nur um kleine Eingaben geht, kann man auch einfach den Scanner immer neu erstellen. Scanner hat einen internen Buffer von 1024 Zeichen. Dann wäre es einfach etwas wie:
Java:
eingabe = new Scanner(System.in).nextInt();

Mir gefällt die Idee nicht, dass hier ständig neue Instanzen von Scanner erzeugt werden. Und es dürfte Probleme geben, wenn längere Eingaben kommen, da dann nur ein Teil im Buffer des ersten Streams war und dann der nächste ab irgend einem Punkt weiter macht ...

Aber warum ich das so bringe: Diese Form des Aufrufs hatten wir ja im Forum auch schon gesehen. Evtl. wurde Scanner so verwendet um eben diese Problematik mit unerwünschtem Buffer-Inhalt los zu werden.
 

Neue Themen


Zurück
Oben