Probleme mit nextInt() und Exception

ernst

Top Contributor
Hallo allerseits,
1)
Mit dem Scanner kann man mit nextInt() Zahlen eingeben.
Gibt man eine Zeichenkette von Ziffern ein, wird diese in den Tastaturpuffer geschrieben.
nextInt() wandelt diese Zeichenkette in eine Zahl um und _leert_ dabei den Tastaturpuffer.

2)
Gibt man dagegen keine Zeichenkette von Ziffern ein, wie z.B. "e" wird eine Exception erzeugt und der Tastaturpuffer - so meine Vermutung - dabei _nicht_ gelöscht.
Meine Vermutung kommt von dem Programm unten:
Wenn man z.B. die Zeichenkette "e" über Tastatur eingibt, so kommt man in eine Endlos-Schleife. Das Programm hält auch nicht mehr an, weil im Tastaturpuffer immer "e" steht.

3)
Ist meine Vermutung korrekt?

4)
Warum steht in der Doku von Oracle nichts von meiner Vermutung ?

5)
Gibt es eine offizielle Doku, in der diese Bugs von Java dokumentiert werden ?

6)
Auf der Seite:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6351708
wird dieser Bug auch nicht aufgelistet.

7)
Ist die Seite
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6351708
eine offizielle Doku aller Java Bugs bzw. wo findet man so eine offizielle Doku ?

mfg
Ernst



=====================================================
Java:
/*
P R O G R A M M D O K U M E N T A T I O N:
nextInt() liest aus dem Tastaturpuffer eine Zeichenkette wie z.B. "123"
und wandelt diese in eine ganze zahl um.
Wenn man allerdings eine Zeichenkette einliest, wie z.B. "e" oder "12x"
kann diese nicht in eine Zahl umgewandelt werden.
Dann wird eine Exception ausgelöst.

Problem:
beim Auslesen einer Zeichenkette, die nicht in eine Zahl umgewandelt werden
kann wie z.B. "e" wird dieser "Restmüll" NICHT aus dem Tastaturpuffer
entfernt. Deswegen kommt das Programm unten in eine Endlos-Schleife.

Offizieller, anerkannter Fehler, siehe:
[URL]http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6351708[/URL]
*/
package scannerproblem1;
import java.util.Scanner;
/**
*
* @author lzbarner
*/
public class Startklasse {

  public static void main(String[] args) {
    System.out.println("Eingabe Integer:");
    System.out.println("Ihre Eingabe war: " + getInput());
  }

 
    protected static int getInput() {
      boolean isCorrectInput = false;
      int inputValue = 0;
      Scanner sc = new Scanner(System.in);

      while (!isCorrectInput) {
        try {
        // Bei einer Eingabe wie z.B. "e" wird dieser Schrott nicht
        // aus dem Tastaturpuffer entfernt. Das Programm springt
        // korrkterweise in den catch-Block. Danach kommt es wieder
        // zu der Zeile: inputValue = sc.nextInt();
        // Weil aber immer noch der Schrott "e" im Tastaturpuffer
        // steht, muß das Programm nicht anhalten und auf eine neue
        // Eingabe warten.
        inputValue = sc.nextInt();
        isCorrectInput = true;
        } catch (Exception ex) {
           System.out.println("Eingabe war nicht vom Typ Integer, bitte erneut   
                                        eingeben:");
           // System.out.println("sc.Next()="+sc.next());
           //ex.printStackTrace();
      }
    }
  return inputValue;
  }
}
 
Zuletzt bearbeitet von einem Moderator:

Dukel

Top Contributor
Wieso machst du dies mit der While Schleife?
Java:
try {
            inputValue = sc.nextInt();
        } catch (Exception e) {
            System.out.println("Eingabe war nicht vom Typ Integer, bitte erneut eingeben:");
            //e.printStackTrace();
        }

Dein Problem ist, das nicht nach einer weiteren Eingabe gefragt wird, da dies außerhalb der Methode passiert.

EDIT: Ach ja. Du musst den Scanner in die While Schleife nehmen, dann funktioniert das auch.

Java:
while (!isCorrectInput) {
       Scanner sc = new Scanner(System.in);
       try {
         inputValue = sc.nextInt();
         isCorrectInput = true;
       } catch (Exception ex) {
         System.out.println("Eingabe war nicht vom Typ Integer, bitte erneut eingeben:");
       }
     }
 

Joose

Top Contributor
@Dukel warum keine Schleife? Er will ja solange etwas eingeben müssen bis eine Zahl eingegeben wurde.
Der Scanner muss nicht in der Schleife initialisiert werden, wozu auch? Mittels den "next...." Methoden wird nach neuen Input geschaut.
 

ernst

Top Contributor
Kein Bug.
Einen passenden Link hast du ja schon gefunden: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6351708
Dort steht ganz unten dass die Methoden so arbeiten wie sie spezifiziert wurden.
[/java]

Wie wurden sie spezifiziert?
Ich habe nicht gelesen, daß der Tastaturpuffer geleert wird.
Außer der Info in
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
"When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method."


mfg
Ernst
 

Joose

Top Contributor
In diesem Fall habe ich nur kurz zusammengefasst was man beim Link lesen kann ;)

Aber du schreibst es ja selber du hast nichts davon gelesen das der Buffer geleert wird im Fehlerfall. Daher sollte man auch nicht davon ausgehen.
 

ernst

Top Contributor
In diesem Fall habe ich nur kurz zusammengefasst was man beim Link lesen kann ;)

Aber du schreibst es ja selber du hast nichts davon gelesen das der Buffer geleert wird im Fehlerfall. Daher sollte man auch nicht davon ausgehen.
Im Fall einer Zeichenkette aus Ziffern wie z.B. "123" steht aber auch nicht, daß der Tastaturpuffer geleert wird. Er wird aber geleert.
Wie soll man dann aber mit dieser Methode nextInt() arbeiten, wenn man nicht weiß, ob der Tastaturpuffer geleert wird oder nicht?

mfg
Ernst
 
K

kneitzel

Gast
Also das Verhalten ist zum einen genau das, was erwartet wird. Wenn ein Token zurück gegeben wird, dann sind Daten gelesen und werden damit aus dem Stream entfernt.
Wenn eine Exception geworfen wird, dann wären die Daten ja weg, wenn sie dadurch aus dem Stream entfernt worden wären. Das wäre ein potentieller Datenverlust. Also unwahrscheinlich, dass etwas so implementiert wurde.

Aber damit das Verhalten klar ist, wurde es entsprechend dokumentiert. Die Stelle ist ja schon zitiert worden.
 

ernst

Top Contributor
Also das Verhalten ist zum einen genau das, was erwartet wird. Wenn ein Token zurück gegeben wird, dann sind Daten gelesen und werden damit aus dem Stream entfernt.
Wenn eine Exception geworfen wird, dann wären die Daten ja weg, wenn sie dadurch aus dem Stream entfernt worden wären. Das wäre ein potentieller Datenverlust. Also unwahrscheinlich, dass etwas so implementiert wurde.
Was ist aber anders, wenn das Objekt sc der Klasse Scanner _innerhalb_ der while-Schleife deklariert und initialisiert wird?
Warum funktioniert es da (keine Endlos-Schleife bei Eingabe von z.B. "e") ?

mfg
E
 
K

kneitzel

Gast
Ich kenne die Implementation von Scanner nicht im Detail. Möglich, dass der Scanner das Token aus dem Stream liest. Damit ist das Token in der Scanner Instanz und nicht mehr auf dem Stream. Wenn Du jetzt ein neues Scanner Objekt erzeugst auf dem Stream, dann kann es nur noch das lesen, was da auf dem Stream ist.

Das ist aber ein Pattern, dass extrem unschön ist. Von einem Stream sollte genau an einer Stelle gelesen werden und nicht von mehreren Instanzen.
 

ernst

Top Contributor
Zitat:
"Ich kenne die Implementation von Scanner nicht im Detail. Möglich, dass der Scanner das Token aus dem Stream liest. Damit ist das Token in der Scanner Instanz und nicht mehr auf dem Stream. Wenn Du jetzt ein neues Scanner Objekt erzeugst auf dem Stream, dann kann es nur noch das lesen, was da auf dem Stream ist."
Ich verstehe diese Argumentation nicht.
Wenn man "e" eingibt befindet sich das "e" immer noch im Tastaturpuffer (= Stream ?) und wird durch nextInt() nicht ausgelesen und dort gelöscht.
Warum sollte diese Regel nicht mehr gelten, wenn sich der Ort der Deklaration ändert bzw. von diesem abhängig sein?

mfg
E
 
K

kneitzel

Gast
Also eine bildliche Beschreibung:
Mal angenommen Du legst Zettel mit irgendwas drauf immer auf einen Stapel (Da bist Du dann sozusagen die Tastatur).
Ich bin dann der Scanner - und meine Aufgabe ist es, immer den untersten Zettel vom Stapel zu nehmen und auszuwerten.
Nun werde ich angesprochen: Gib mir mal bitte die nächste Zahl. Also nehme ich den untersten Zettel und schaue drauf. Da sehe ich aber jetzt ein "e" also sage ich Dir: Sorry, da ist keine Zahl drauf! Und behalte den Zettel aber in der Hand!
Jetzt kann man mich erneut ansprechen: gib mit die nächste Zahl. Ich habe aber noch den Zettel in der Hand und da steht weiterhin "e" drauf. Also werde ich wieder keine Zahl nennen können.
Man könnte mir sagen: Lege den Zettel weg. Dann wäre es möglich, mich erneut nach einer Zahl zu fragen. Da ich keinen Zettel in der Hand halte, müsste ich mir den nächsten Zettel nehmen.
Oder man könnte hingehen und sagen: Du bist ja blöd - willst mir einfach keine Zahl nennen. Daher suchst Du Dir jemand anderes, der sich einen Zettel nehmen kann und Dir die Zahl sagen kann.

Das kann ganz böse sein, denn wenn ich nicht mehr Zettel auswerten soll gehe ich hin und zerstöre den ganzen Papierstapel mit allen Zetteln und dem Platz für den Stapel. Andere können dann auch keine Zettel mehr wegnehmen. (Das ist die close() Methode. Close schließt auch den Stream.)

Diese eigenen Buffer sind teilweise normale Dinge. Ich muss ja Daten, die ankommen, lesen, bis ich ein Token zusammen habe. Ein Beispiel aus der Vergangenheit war z.B. bei mir das Lesen von Daten aus einem Netzwerk Stream: Die Daten sind in Paketen gekommen und waren dabei aber nicht in meine "Token" getrennt. Trenner war bei mir ein Newline und ich musste also immer Daten lesen bis ich endlich ein Newline hatte. Dann konnte ich die Nachricht erst auswerten.
 
K

kneitzel

Gast
Und da ich Vermutungen hasse und mich das selbst etwas wurmt habe ich einfach einmal die Implementation der Scanner Klasse im openjdk angesehen:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/8cc500af2454/src/share/classes/java/util/Scanner.java

Zum einen findet man direkt einen internen Buffer:
Code:
    // Internal buffer used to hold input
    private CharBuffer buf;
    // Size of internal character buffer
    private static final int BUFFER_SIZE = 1024; // change to 1024;
    // The index into the buffer currently held by the Scanner
    private int position;

Und dann findet man im Code natürlich auch die Nutzung des Caches:
Code:
    /**
    * Scans the next token of the input as an <tt>int</tt>.
    *
    * <p> An invocation of this method of the form
    * <tt>nextInt()</tt> behaves in exactly the same way as the
    * invocation <tt>nextInt(radix)</tt>, where <code>radix</code>
    * is the default radix of this scanner.
    *
    * @return the <tt>int</tt> scanned from the input
    * @throws InputMismatchException
    *        if the next token does not match the <i>Integer</i>
    *        regular expression, or is out of range
    * @throws NoSuchElementException if input is exhausted
    * @throws IllegalStateException if this scanner is closed
    */
    public int nextInt() {
        return nextInt(defaultRadix);
    }
    /**
    * Scans the next token of the input as an <tt>int</tt>.
    * This method will throw <code>InputMismatchException</code>
    * if the next token cannot be translated into a valid int value as
    * described below. If the translation is successful, the scanner advances
    * past the input that matched.
    *
    * <p> If the next token matches the <a
    * href="#Integer-regex"><i>Integer</i></a> regular expression defined
    * above then the token is converted into an <tt>int</tt> value as if by
    * removing all locale specific prefixes, group separators, and locale
    * specific suffixes, then mapping non-ASCII digits into ASCII
    * digits via {@link Character#digit Character.digit}, prepending a
    * negative sign (-) if the locale specific negative prefixes and suffixes
    * were present, and passing the resulting string to
    * {@link Integer#parseInt(String, int) Integer.parseInt} with the
    * specified radix.
    *
    * @param radix the radix used to interpret the token as an int value
    * @return the <tt>int</tt> scanned from the input
    * @throws InputMismatchException
    *        if the next token does not match the <i>Integer</i>
    *        regular expression, or is out of range
    * @throws NoSuchElementException if input is exhausted
    * @throws IllegalStateException if this scanner is closed
    */
    public int nextInt(int radix) {
        // Check cached result
        if ((typeCache != null) && (typeCache instanceof Integer)
            && this.radix == radix) {
            int val = ((Integer)typeCache).intValue();
            useTypeCache();
            return val;
        }
        setRadix(radix);
        clearCaches();
        // Search for next int
        try {
            String s = next(integerPattern());
            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
                s = processIntegerToken(s);
            return Integer.parseInt(s, radix);
        } catch (NumberFormatException nfe) {
            position = matcher.start(); // don't skip bad token
            throw new InputMismatchException(nfe.getMessage());
        }
    }

Das erst einmal nur als Anhalt dafür, dass meine Vermutung richtig ist. Natürlich müsste man noch die next Funktion genauer ansehen. Dort sieht man dann die Nutzung des buffers im Detail mit der Funktion getCompleteTokenInBuffer.

Also ich gehe dem jetzt nicht noch mehr im Detail nach - was ich jetzt gesehen habe reicht mir soweit.
 

ernst

Top Contributor
Also das Verhalten ist zum einen genau das, was erwartet wird. Wenn ein Token zurück gegeben wird, dann sind Daten gelesen und werden damit aus dem Stream entfernt.
ok, aber _nur_ wenn es eine Zeichenkette ist, wie z.B. "123"

Wenn eine Exception geworfen wird, dann wären die Daten ja weg, wenn sie dadurch aus dem Stream entfernt worden wären. Das wäre ein potentieller Datenverlust. Also unwahrscheinlich, dass etwas so implementiert wurde.
Genau und deswegen ist das "e" immer noch auf dem Stapel
Also auch bei deinem Stapel-Modell.

Mal angenommen Du legst Zettel mit irgendwas drauf immer auf einen Stapel (Da bist Du dann sozusagen die Tastatur).
Ich bin dann der Scanner - und meine Aufgabe ist es, immer den untersten Zettel vom Stapel zu nehmen und auszuwerten.
Nun werde ich angesprochen: Gib mir mal bitte die nächste Zahl. Also nehme ich den untersten Zettel und schaue drauf. Da sehe ich aber jetzt ein "e" also sage ich Dir: Sorry, da ist keine Zahl drauf! Und behalte den Zettel aber in der Hand!
Nein, er ist nicht in deiner Hand. Du hast ihn nur gelesen. Er ist immer noch auf dem Stapel (sonst
potentieller Datenverlust --> Zitat von dir).
Wo habe ich dich falsch verstanden ?

mfg
E
 
K

kneitzel

Gast
Du hast den Stream. Und Du hast den Scanner. Der Scanner hat einen eigenen Zwischenspeicher. Daher sind die Daten aus dem Stream raus und im Scanner drin. Das ist doch auch das Verhalten, dass Du beobachtet hast, wenn ich Dich richtig verstanden habe.

Und ein Datenverlust droht nicht, so Du sauber arbeitest. Sieh Streams als eine Art Rohr an. Du hast nur einen Eingang und einen Ausgang. Wenn Du aber meinst, viele Ausgänge zu haben, dann ist es Dein Problem und nicht das Problem des Streams.
 

ernst

Top Contributor
Erst mal Dank an alle für die vielen Feedbacks.
Du hast den Stream. Und Du hast den Scanner. Der Scanner hat einen eigenen Zwischenspeicher. Daher sind die Daten aus dem Stream raus und im Scanner drin. Das ist doch auch das Verhalten, dass Du beobachtet hast, wenn ich Dich richtig verstanden habe.
Ok, das kann ich nachvollziehen.
Aber müsste diese Beschreibung und dieses Verhalten nicht in die Doku zu der Klasse Scanner?

Und ein Datenverlust droht nicht, so Du sauber arbeitest. Sieh Streams als eine Art Rohr an. Du hast nur einen Eingang und einen Ausgang. Wenn Du aber meinst, viele Ausgänge zu haben, dann ist es Dein Problem und nicht das Problem des Streams.
Was meinst du mit "viele Ausgänge" im Zusammenhang mit diesem Thread bzw. dem von mir beschriebenen Problem ?

mfg
E
 
K

kneitzel

Gast
Also in der Programmierumgebung würde es bedeuten, dass ich auf einem Stream mehrere "Abnehmer" erzeuge. Also z.B. zwei Scanner auf einem Stream. Das ist einfach ein No Go.

Und im Übertragenen Sinne wäre es eine Wasserleitung an der mehrere Wasserhähne sind. Wasser, das am ersten Wasserhahn vorbei gelaufen ist, wird nicht mehr aus dem ersten Wasserhahn laufen. Es ist keine saubere Abnahme von Werten.

Und diese Buffer müssen nicht explizit erwähnt werden aus meiner Sicht. Das ist eine Logik, die gekapselt ist und die Dich nicht zu interessieren hat. Und es ist ein übliches, normales Vorgehen
 

ernst

Top Contributor
Also in der Programmierumgebung würde es bedeuten, dass ich auf einem Stream mehrere "Abnehmer" erzeuge. Also z.B. zwei Scanner auf einem Stream. Das ist einfach ein No Go.
wenn man _innerhalb_ der while-Schleife (wie oben vorgeschlagen wurde) eine Objektvariable vom Typ Scanner deklariert und initialisiert, dann hat man den von dir geschilderten Fall: mehree Abnehmer auf dem gleichen Stream ( = Tastaturpuffer). Ist das also ein no-go ?

Und diese Buffer müssen nicht explizit erwähnt werden aus meiner Sicht. Das ist eine Logik, die gekapselt ist und die Dich nicht zu interessieren hat. Und es ist ein übliches, normales Vorgehen
Was gekapselt ist, geht mich nichts an. Das sehe ich ein.
Wie ich aber nextInt() verwenden kann geht den Nutzer der Funktion schon etwas an.
Und daß "zwei Scanner auf einem Stream" ein no-go sind geht den Nutzer der Funktion auch etwas an. Das sollte dann schon dokumentiert sein.

mfg
E
 
Zuletzt bearbeitet von einem Moderator:
K

kneitzel

Gast
Also ich sehe hier mehrere Punkte:

a) Wie geht man an eine Entwicklungsarbeit heran?
Meine Meinung nach erfordert das immer eine intensive Recherche. Sowohl zum eigentlichen Problemgebiet (Man muss die Aufgabenstellung verstanden haben) aber auch zu den eingesetzten Hilfsmitteln. Dazu gehören Tools und Frameworks.
So muss jemand die Klassen kennen, die man nutzen will. Wer die Klasse Scanner nutzen will, der sollte die Klasse auch kennen. Und dazu gehört dann das Lesen der Dokumentation. Und die Klasse Scanner hat eine sehr große Dokumentation.
Desweiteren sollte man die implementierten Interfaces kennen. So gibt es das Closable Interface. Eine Instanz, die dies implementiert, will geschlossen werden. Da Java keine "native"/"unmanaged" Dinge kennt, ist es hier nicht so wichtig, wie in .Net das Disposable. (Es sei denn, man hat JNI im Einsatz. Dann wird es ebenso wichtig!) Etwas, das geschlossen werden will, sollte auch geschlossen werden. Dafür gibt es dann auch extra so Dinge wie try with resources.

b) Unsaubere Entwicklung ist ein Problem
Es ist einfach ein Problem, wenn jemand unsauber entwickelt. Da kommt zwar eine Exception aber ich muss ja nicht verstehen, was da abgeht. Ich frickel mir dann schon eine Lösung zusammen. Closable? Interessiert mich nicht!
So geht das nicht. Wenn Du da einen Scanner nutzt, dann ruf doch auch mal close auf oder nutz try with ressources. Und schon merkst Du, dass Dein angedachtes Konstrukt so eben nicht funktioniert.
Lies die Dokumentation der Klasse - und schon findest Du Hinweise, was bei der Exception zu beachten ist.

c) Inhalt der Dokumentation von Scanner und wo sollen diese Informationen rein?
Ein Punkt ist, in wie weit gewisse Dokumentation nicht in den "Kopf" der Doku gehört sondern in die Beschreibung der Klasse. Aber das würde bedeuten, dass bei relativ vielen Funktionen genau dieser Hinweis zu der Exception rein müsste. Aber es macht doch keinen Sinn, einen Kommentar X mal zu kopieren. Wer eine Klasse verwendet, wird doch immer die Doku der Klasse lesen.
Ein anderer Punkt ist die Frage, was alles dokumentiert gehört. Genereller Umgang mit Streams gehört da meiner Meinung nach nicht rein. Scanner ist ja kein Stream sondern nutzt den Stream nur. Wer also etwas über Streams erfahren möchte, der sollte doch bitte die Dokumentation dort lesen.
Ebenso ist evtl. die Frage zu beantworten, was an Grundlagen noch in eine Referenz wie hinein gehört.
Es gibt ja durchaus mehrere Dokumentationen und da muss man dann genau überlegen, wo was hinein gehört. So gibt es neben der Dokumentation des Frameworks ja auch noch grundlegende Dokumentation: JLS / JVMS fällt mir da so ein. Da können gewisse Grundlagen auch erläutert sein, denn es gibt ja auch Schnittstellen zu eben genau diesen Dokumenten.

Aber das sind nur so Gedanken von mir und meine Sichtweise. Ich bin niemand, der dies festlegen würde oder da irgendwie ausschlaggebend wäre. Es gibt ja auch Wege, Vorschläge und Bugreports einzubringen, so dass man so Themen auch an Verantwortliche herantragen kann. Auch wichtig: Meine Sichtweise sollte nicht wertend aufgefasst werden. Jeder soll so arbeiten, wie er möchte. Und die Anforderungen an jemanden, der Vollzeit Entwickler ist, dürfte anders sein als die Anforderung an einen Hobby-Entwickler oder Anfänger.
 

ernst

Top Contributor
1)
Also ich sehe hier mehrere Punkte:
a) Wie geht man an eine Entwicklungsarbeit heran?
...
Danke für deine Sicht der Dinge

2)
Kannst du mir noch meine andere Frage im letzten Posting beantworten?
"wenn man _innerhalb_ der while-Schleife (wie oben vorgeschlagen wurde) eine Objektvariable vom Typ Scanner deklariert und initialisiert, dann hat man den von dir geschilderten Fall: mehrere Abnehmer auf dem gleichen Stream ( = Tastaturpuffer). Ist das also ein no-go ?"

mfg
E
 
K

kneitzel

Gast
Ja, das ist ein no-go. Denn zum einen setzt man auf einen Stream nicht mehrfach auf (IMHO) und zum anderen wird eine Closable Instanz nicht geschlossen. (Sobald Du das machst, würde dieses Konstrukt ehh nicht mehr funktionieren.)
 

ernst

Top Contributor
Ja, das ist ein no-go. Denn zum einen setzt man auf einen Stream nicht mehrfach auf (IMHO) und zum anderen wird eine Closable Instanz nicht geschlossen. (Sobald Du das machst, würde dieses Konstrukt ehh nicht mehr funktionieren.)
1)
Was meinst du mit "zum anderen wird eine Closable Instanz nicht geschlossen"?
2)
In meinem Programm wurde _außerhalb_ einer while-Schleife deklariert:
Scanner sc = new Scanner(System.in);
Wo wurde diese geschlossen?
Meinst du so etwas wie sc.close() ??

mfg
E
 
K

kneitzel

Gast
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
"All Implemented Interfaces:
Closeable, AutoCloseable, Iterator<String>"

Das wichtige Interface ist AutoCloseable:
https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html
"A resource that must be closed when it is no longer needed."

Somit steht die Aussage aus der Dokumentation im Raum, dass Scanner geschlossen werden muss, wenn es nicht mehr benötigt wird.

Und Du hast Scanner nicht geschlossen. Das ist ein Kritikpunkt. Mag man drauf verzichten wollen, gerade bei kleinen Applikationen. Was interessieren mich Ressourcen, wenn die App nach 1 Min ehh wieder beendet ist? Das ist dann dieses "Jeder soll so entwickeln, wie er möchte oder es für richtig findet". Aber bei Diskussionen um Clean Code und so fällt dies meiner Meinung nach durch (Ist meine Meinung, mag auch andere Meinungen geben. Aber die Dokumentation habe ich jetzt einfach einmal wieder gegeben in kleinen Auszügen.)
 

ernst

Top Contributor
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
"All Implemented Interfaces:
Closeable, AutoCloseable, Iterator<String>"

Das wichtige Interface ist AutoCloseable:
https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html
"A resource that must be closed when it is no longer needed."
Somit steht die Aussage aus der Dokumentation im Raum, dass Scanner geschlossen werden muss, wenn es nicht mehr benötigt wird.
Und Du hast Scanner nicht geschlossen. Das ist ein Kritikpunkt. Mag man drauf verzichten wollen, gerade bei kleinen Applikationen. Was interessieren mich Ressourcen, wenn die App nach 1 Min ehh wieder beendet ist? Das ist dann dieses "Jeder soll so entwickeln, wie er möchte oder es für richtig findet". Aber bei Diskussionen um Clean Code und so fällt dies meiner Meinung nach durch (Ist meine Meinung, mag auch andere Meinungen geben. Aber die Dokumentation habe ich jetzt einfach einmal wieder gegeben in kleinen Auszügen.)

1)
Ich gebe dir natürlich vollkommen recht, daß man sauberen Code produzieren soll und die Regeln und Empfehlungen der Doku beachten muß, sonst kann man sich nicht beklagen, wenn es irgendwo klemmt.

2)
In dem Programm unten habe ich meine frühere Version etwas abgeändert.
In der while-Schleife wird ein Scannerobjekt immer wieder angelegt, dann aus dem Tastaturpuffer gelesen und danach das Scannerobjekt wieder geschlossen (zerstört) und damit der Tastaturpuffer wieder gelöscht.
Warum geht das Programm aber wieder in eine Endlosschleife, wenn man z.B. "e" eingibt?

mfg
E



Java:
package scannerproblem2;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.Scanner;
public class Startklasse {
  public static void main(String[] args) {
  System.out.println("Eingabe Integer:");
  System.out.println("Ihre Eingabe war: " + getInput());
  }

 
  protected static int getInput() {
    boolean isCorrectInput = false;
    int inputValue = 0;
    // Scanner sc = new Scanner(System.in);

    while (!isCorrectInput) {
      Scanner sc = new Scanner(System.in); 
      try {
        inputValue = sc.nextInt();
        isCorrectInput = true;
      } catch (InputMismatchException ex) {
        System.out.println("Eingabe war vom Typ InputMismatchException, bitte erneut eingeben:");
      } catch (NoSuchElementException ex) {
      System.out.println("Eingabe war vom Typ NoSuchElementException, bitte erneut eingeben:");
      } catch (IllegalStateException ex) {
      System.out.println("Eingabe war vom Typ IllegalStateException, bitte erneut eingeben:");
      }
      sc.close(); 
    }
  return inputValue;
  }
}
 

thecain

Top Contributor
Es ist davon abzuraten in einem Loop mehere Scanner zu erstellen. v.a. wenn System.in geschlossen wird.
Wenn du den internen Buffer löschen willst, kannst du dies mit einem nextLine machen.

Beispiel:
Java:
public class Startklasse {
    public static void main(String[] args) {
        System.out.println("Eingabe Integer:");
        System.out.println("Ihre Eingabe war: " + getInput());
    }


    protected static int getInput() {
        boolean isCorrectInput = false;
        int inputValue = 0;
        // Scanner sc = new Scanner(System.in);
        Scanner sc = new Scanner(System.in);
        while (!isCorrectInput) {

            try {
                inputValue = sc.nextInt();
                isCorrectInput = true;
            } catch (InputMismatchException ex) {
                System.out.println("Eingabe war vom Typ InputMismatchException, bitte erneut eingeben:");
            } catch (NoSuchElementException ex) {
                System.out.println("Eingabe war vom Typ NoSuchElementException, bitte erneut eingeben:");
            } catch (IllegalStateException ex) {
                System.out.println("Eingabe war vom Typ IllegalStateException, bitte erneut eingeben:");
            }
            sc.nextLine();
        }
        sc.close();
        return inputValue;
    }
}
 
K

kneitzel

Gast
Bitte schau genau, welche Exceptions kommen und lies nach, was die Exception bedeutet.
Nur die erste Exception kommt wegen dem "e". Danach kommt eine andere Exception. Und der solltest Du einmal nachgehen.
Die Antwort steht in der Doku vom Scanner - wichtig ist, was die Funktion close() alles macht.
 

ernst

Top Contributor
Bitte schau genau, welche Exceptions kommen und lies nach, was die Exception bedeutet.
Nur die erste Exception kommt wegen dem "e". Danach kommt eine andere Exception. Und der solltest Du einmal nachgehen.
Die Antwort steht in der Doku vom Scanner - wichtig ist, was die Funktion close() alles macht.

Es wird genau eine Exception
"InputMismatchException" ausgegeben und dann beliebig viele Exceptions
"NoSuchElementException".
Die Antwort in der Doku:
"When a Scanner is closed, it will close its input source if the source implements the Closeable interface."
hilft mir da nicht weiter und die Antwort ( bei nextInt() )
"NoSuchElementException - if input is exhausted" sagt mir auch nicht, warum es zur Endlos-Schleife kommt.

mfg
E
 
K

kneitzel

Gast
Also wenn ein Stream geschlossen worden, dann kann aus diesem nicht mehr gelesen werden. Also ist folgendes passiert:
- Du öffnest einen Scanner auf System.in. Soweit ganz gut.
- Du rufst nextInt() auf. Dadurch liest der Scanner so lange von System.in, bis eine Zeile eingegeben wurde und die dann ausgewertet werden kann (Mindestens die Zeile ist dann im Scanner und nicht mehr im Stream. Das ist aber nebensächlich).
- Beim Auswerten fällt dem Scanner nun auf, dass es kein Integer ist. Also wird die InputMismatchException geworfen. Die Eingabe bleibt aber weiterhin im Scanner.
- Nun rufst Du close auf dem Scanner auf. Dadurch wird System.in auch geschlossen.
- Hinweis: Wenn Du nach dem close() noch einmal versuchst, etwas zu lesen, würdest Du die IllegalStateException bekommen. Scanner ist in einem Status, in dem dieses Lesen nicht mehr erlaubt ist.
- Nun erstellst Du erneut einen Scanner auf System.in. System.in ist geschlossen, d.h. da sind keine Zeichen mehr zu lesen.
- Nun rufst Du nextInt aus. Da aber keine Zeichen mehr gelesen werden können (beim Lesen aus einer Datei entspräche dies etwa dem Dateiende), kommt nun die NoSuchElementExeption. Es gibt kein Element mehr, das gelesen / ausgewertet werden könnte.
- Nun rufst du wieder close auf, das ändert aber nicht mehr viel, da der Stream ja schon geschlossen ist.
- Nun fängst Du wieder bei dem Punkt mit einem neuen Scanner an. Das am Stream hat sich ja nichts geändert, so dass Du wieder in die NoSuchElementException hinein läufst.
 

ernst

Top Contributor
Also wenn ein Stream geschlossen worden, dann kann aus diesem nicht mehr gelesen werden. Also ist folgendes passiert:
...
- Nun rufst Du close auf dem Scanner auf. Dadurch wird System.in auch geschlossen.geändert...

Danke für diese tiefgehenden Infos.
1)
"Nun rufst Du close auf dem Scanner auf. Dadurch wird System.in auch geschlossen."
Ok, aber in der Doku des Scanner steht:
"When a Scanner is closed, it will close its input source if the source implements the Closeable interface"
Wo hat aber System das Interface Closeable implementiert.
In der Doku habe ich nicht entdeckt

2)
Ein einziges sc.close() bewirkt also, daß man nichts mehr überTastatur eingeben kann.
Das verwudert mich etwas.
Deswegen meine Frage:
Wie kann man System.in wieder öffnen,
damit wieder etwas über Tastatur eingegeben werden kann?

mfg
E



eingeben
 

thecain

Top Contributor
K

kneitzel

Gast
Also um auf Deine Fragen einzugehen:
1) Schauen wir uns System an: https://docs.oracle.com/javase/7/docs/api/java/lang/System.html
in ist ein InputStream: https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
und implementiert Closable, Autoclosable.

2) System.in ist nicht so einfach neu zu öffnen. Daher sollte man es nicht schließen. Daher ist die Lösung auch niemals, einfach ein neues Scanner Objekt zu öffnen. Statt dessen öffnet man einen Scanner und behält diese eine Instanz, so lange man eben diese benötigt.
Und wenn dann ein Problem wie in diesem Thread auftritt, dass ein nextInt eben eine TypeMismatchException wirft, dann kümmert man sich einfach um die falsche Eingabe. Diese könnte per skip übersprungen oder z.B. durch das Auslesen der ganzen Zeile verarbeitet werden.
 

ernst

Top Contributor
Also um auf Deine Fragen einzugehen:
1) Schauen wir uns System an: https://docs.oracle.com/javase/7/docs/api/java/lang/System.html
in ist ein InputStream: https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
und implementiert Closable, Autoclosable.
Du hast recht!

[/QUOTE]
2) System.in ist nicht so einfach neu zu öffnen. Daher sollte man es nicht schließen. Daher ist die Lösung auch niemals, einfach ein neues Scanner Objekt zu öffnen. Statt dessen öffnet man einen Scanner und behält diese eine Instanz, so lange man eben diese benötigt.
[/QUOTE]
Ok, aber angenommen man schließt System.in mit z.B. sc.close().
Ein einziges sc.close() bewirkt also, daß man nichts mehr überTastatur eingeben kann.
Kann man dann _nie_ mehr innerhalb seines _ganzen_ Quellcodes etwas überTastatur eingeben?
Oder gilt das nur auf die umgebende Methode (und wenn ja warum) ?

mfg
E
 
K

kneitzel

Gast
Nein, es ist nicht möglich, die Console erneut zu öffnen. Und hier würde auch die Regel gelten, dass Du System.in nicht zu schließen hast, da Du es nicht geöffnet hast.

Wenn Du viel mit dem scanner arbeiten willst und musst, dann würde ich hier evtl. eine eigene Klasse schreiben, die einen Scanner hält und diesen für alle verfügbar macht. Ein Singleton Pattern würde mir da gerade in den Sinn kommen. Wichtig wäre, dass man hier auch Dinge wie Multithreading berücksichtigt.

Es gibt da viele Ideen und Vorschläge. http://stackoverflow.com/questions/...ossible-to-re-open-system-in-after-closing-it wäre so ein Thread. Die vorgeschlagene Lösung dort ist aber in meinen Augen nicht wirklich akzeptabel aus Gründen, die wir ja prinzipiell hier schon erörtert haben. (Dort wird dann einfach das close() überschrieben und so lassen sich dann viele Scanner auf einem Stream öffnen. Nur jeder Scanner hat dann halt auch seinen internen Buffer und Daten, die einmal gelesen wurden vom Stream stehen dann einem anderen Scanner nicht mehr zur Verfügung. Die Gefahr eines Datenverlustes ist also denkbar.

Scanner selbst ist final, daher kann man davon nicht ableiten. Aber eine Klasse GlobalConsoleScanner wäre denkbar, die einen private Konstruktor hat, einen getScanner() Aufruf der halt die Singleton Instanz erzeugt und dann alle Funktionen von Scanner erneut implementiert und der die Aufrufe 1:1 an den internen Scanner weiter gibt. Ein close() gibt es dann nicht und es wird auch keinen parametrisierten Konstruktor geben.

Aber das ist auch nur etwas, das ich so aus dem Stehgreif behaupten würde. Das Design müsste man sich genau ansehen um dann evtl. weitere Verbesserungen zu machen.

Konrad
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
C Probleme beim Erstellen eines runnable-jar files Allgemeine Java-Themen 1
S Umstellung von File auf Path - Probleme mit Stream Allgemeine Java-Themen 5
C Probleme mit javax.mail.Session Allgemeine Java-Themen 8
M tomcat probleme Allgemeine Java-Themen 1
N Division macht Probleme Allgemeine Java-Themen 14
B Java Reflection Probleme beim wehcselseitigen Referenzieren zweier Klassen/Objekte Allgemeine Java-Themen 14
MarvinsDepression Probleme mit relativem Dateipfad Allgemeine Java-Themen 1
G Geotools Probleme nach PC-Wechsel Allgemeine Java-Themen 6
nibe1501 GUI Probleme Allgemeine Java-Themen 16
C Probleme mit dem WindowBuilder Allgemeine Java-Themen 3
P Selenium . Probleme ein Iron Icon Element anzusprechen Allgemeine Java-Themen 2
B Compiler-Fehler Probleme beim Kompilieren mit Jsoup Allgemeine Java-Themen 8
K VisualVM Profiling Remote Probleme Allgemeine Java-Themen 1
O Leerzeichen und Umlaute im Pfad einer Java Applikation machen Probleme Allgemeine Java-Themen 13
M Probleme bei Eclipse wenn ich entpacke Allgemeine Java-Themen 15
D Regex Probleme Allgemeine Java-Themen 2
M Probleme jar datei. Allgemeine Java-Themen 2
L Vererbung Verständnis Probleme Vererbung Allgemeine Java-Themen 2
Dann07 Probleme mit OpenAL Allgemeine Java-Themen 0
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
V Compiler-Fehler Online Compiler Probleme Allgemeine Java-Themen 4
M Probleme mit Negamax-Algorithmus Allgemeine Java-Themen 29
M Probleme mit BigDecimal Allgemeine Java-Themen 1
T Probleme mit NumberFormat Allgemeine Java-Themen 5
J Probleme exe-Start mit Task Scheduler Allgemeine Java-Themen 1
B Input/Output Probleme beim Ausführen von Shell-Befehlen mit Java Allgemeine Java-Themen 28
J Probleme beim einbinden von Zip4j library Allgemeine Java-Themen 6
F Variablen Palindromzahl (Probleme mit Methode) Allgemeine Java-Themen 9
K Data Konverter - Probleme mit Byte[] Kodierung Allgemeine Java-Themen 3
T Probleme mit dem Pfad zum Propertie file Allgemeine Java-Themen 7
H Swing HashMap zu Tabelle macht mir Probleme Allgemeine Java-Themen 4
Neoline Interpreter-Fehler Probleme mit Arrays.toString Allgemeine Java-Themen 7
F SQLite mit Java / Probleme beim INSERT Befehl Allgemeine Java-Themen 4
J Erste Schritte Probleme mit der Hauptklasse Allgemeine Java-Themen 14
J Tetris Probleme bei Klassen Allgemeine Java-Themen 14
J MinMax VierGewinnt Probleme Allgemeine Java-Themen 22
J Probleme mit CodeCoverage und Lombok Equals Allgemeine Java-Themen 1
S Eclipse Probleme beim Implementieren / Ausführen von jUnit 5-Test Suites Allgemeine Java-Themen 14
R Snake Probleme Allgemeine Java-Themen 2
A Probleme beim Verstehen einer Aufgabenstellung Allgemeine Java-Themen 11
RalleYTN 3D Objekt Translation basierend auf Rotation (Probleme mit Z Rotation) Allgemeine Java-Themen 0
Bluedaishi Druck Probleme mit PDF dateien Allgemeine Java-Themen 4
G Ant Probleme bei einer Installation die Apache ant+ivy verwendet Allgemeine Java-Themen 14
E TableView Probleme Allgemeine Java-Themen 7
perlenfischer1984 Probleme beim Mocken Allgemeine Java-Themen 6
S Kaffemaschine Programmierung Probleme Allgemeine Java-Themen 2
K Threads Runtime und Process Probleme Allgemeine Java-Themen 3
S Probleme mit unterschiedlichen Java-Versionen (Mac OS X 10.11) Allgemeine Java-Themen 0
S Event Handling keyPressed()-Probleme Allgemeine Java-Themen 2
VfL_Freak Große und seltsame Probleme nach Java-Update auf V1.8.0_91 Allgemeine Java-Themen 3
P Probleme mit Grafik (Java) Allgemeine Java-Themen 6
R probleme beim starten von jar unter linux Allgemeine Java-Themen 2
H Probleme mit DAY_OF_WEEK Allgemeine Java-Themen 4
Arif Probleme mit NullPointerException Allgemeine Java-Themen 2
Streeber Probleme mit AWT-EventQueue: ArrayList Elemente hinzufügen Allgemeine Java-Themen 1
D Performance-Probleme mit Joda-Time Allgemeine Java-Themen 3
M Probleme beim rechnen, bei Zahlen mit führenden Nullen. Allgemeine Java-Themen 7
RalleYTN Probleme mit Encrypting Allgemeine Java-Themen 10
M Probleme mit Schriftarten PDFBox Allgemeine Java-Themen 3
J Probleme mit der Java-Runtime Allgemeine Java-Themen 10
G Probleme mit BufferedWriter und URL Allgemeine Java-Themen 4
S Probleme mit meinem MacBook Pro DRINGEND HILFE erbeten! Allgemeine Java-Themen 17
Androbin Interpreter-Fehler Probleme mit Rekursion - StackOverflowError Allgemeine Java-Themen 8
E JCuda-0.6.5 Probleme beim ausführen der Datei Allgemeine Java-Themen 0
M Runtime.exec() verursacht auf manchen Systemen Probleme - Ursache unklar Allgemeine Java-Themen 2
W JNDI - LDAP - Probleme beim editieren von Usern Allgemeine Java-Themen 0
R DBUnit Performance Probleme Allgemeine Java-Themen 0
S Probleme mit Collection Allgemeine Java-Themen 7
L Probleme mit Jar Allgemeine Java-Themen 6
N Zahlensysteme umrechnen; Probleme beim Umwandeln Allgemeine Java-Themen 4
K OOP OOP Gui Spiel + Vererbungen Probleme durch Nichtwissen!! Allgemeine Java-Themen 1
F Java Native/Shared Library (.so) laden macht Probleme Allgemeine Java-Themen 3
J Synchronized Probleme Allgemeine Java-Themen 7
J Java Progressbar & Download Probleme Allgemeine Java-Themen 10
S Probleme mit dem filechooser Allgemeine Java-Themen 1
J Comperator Probleme Allgemeine Java-Themen 4
A Probleme beim auslesen von Quelltext (HTML) Allgemeine Java-Themen 5
S Probleme mit Webappplikation Allgemeine Java-Themen 5
L Plötzlich Probleme mit der JVM :( Allgemeine Java-Themen 6
S starke performance probleme des forums Allgemeine Java-Themen 10
K Probleme bei Berechnung der Komplexität Allgemeine Java-Themen 7
R JRE Ablaufdatum seit 7u10 - Probleme bei selbst ausgelieferter JRE bekannt? Allgemeine Java-Themen 3
H Reg Exp Probleme Allgemeine Java-Themen 5
M Classpath Probleme bei JAR Generierung Allgemeine Java-Themen 2
S Probleme mit JAVA-Installation Allgemeine Java-Themen 3
D Probleme bei for-Schleife Allgemeine Java-Themen 4
R Probleme mit Javadoc Allgemeine Java-Themen 2
G Gson Probleme Allgemeine Java-Themen 2
P KI für TicTacToe programmieren > Probleme Allgemeine Java-Themen 2
M Google App Engine macht Probleme Allgemeine Java-Themen 4
H Probleme mit finally-Block und close() Allgemeine Java-Themen 4
F 2d array probleme Allgemeine Java-Themen 2
M 3D-Grafik Probleme beim drehen von Objekten Allgemeine Java-Themen 9
T Interface Probleme Allgemeine Java-Themen 8
C Eclipse Probleme bei selbst erstelltem Algorithmus Allgemeine Java-Themen 2
M Probleme mit String in Label übergeben. Allgemeine Java-Themen 6
H MediaManager Fragen/Probleme Allgemeine Java-Themen 6
U Probleme mit Kopiervorgang Allgemeine Java-Themen 3
S Probleme beim Auslesen einer Liste Allgemeine Java-Themen 8
S CardLayout Probleme (Zinsrechner) Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben