Frage von alexG93, 73

Java Programm : Wieso wird die Ausgabe zwei mal hintereinander angezeigt?

do{     
  
  System.out.println(Math.floor(Math.random()*2));

  in.read();
  
}  while (true) ;

Es soll eine 0 oder 1 mit 50/50 Chance ausgegeben werden, zwischen jeder Ausgabe soll auf einen beliebigen Tastendruck gewartet werden.

DIe aller erste Ausgabe stimmt: https://gyazo.com/2908fc46443caaf741edba54dbded52b aber danach wird pro Tastendruck immer zwei mal ausgegeben. Wieso?

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von TeeTier, Community-Experte für programmieren, 20

Weil du vermutlich Windows benutzt, und dabei ein ENTER-Tastendruck in eine Kombination aus CR und LF umgewandelt wird, was 2 Zeichen sind.

Da du rohe Bytes anstelle von Chars oder Strings liest, wird dabei ein Zeilenende auch nicht in ein einfaches "\n" umgewandelt, und du erhältst einmal ein '\r' und sofort danach ein '\n' - wie gesagt, bei nur einem einzigen Tastendruck!

Aus diesem Grunde: Einmal ENTER == zwei Zeilen println()

Du musst den Eingabepuffer VOR "in.read()" leeren! Je nachdem welche Spezialisierung von InputStream du verwendest, existiert entweder eine Art "flush()" oder du machst das am besten mit einer Kombination aus "available()" und "skip()" in einer Schleife ... wobei das Ganze Pfusch ist und man eigentlich eine andere Klasse für deine Aufgabe einsetzt. :)

PS: Das ist übrigens auch der Grund, warum dein Code auf Nicht-Windows-Systemen der anderen Antworter tadellos funktioniert! Das Detail steckt also im Teufel ... oder umgekehrt! :)

Kommentar von TeeTier ,

PPS: Um dich nicht dumm sterben zu lassen:

Füge folgenden Code einfach DIREKT nach "in.read()" ein:

while (in.available()) in.read();

Ich weiß, das ist nicht gerade elegant (im Gegenteil: sogar eher QnD), aber den Stil kann sich jeder anpassen, wie er lustig ist.

Viel Spaß damit! :)

Kommentar von alexG93 ,

Sowas ähnliches hab ich mir schon gedacht, in c++ gibts ja das fflush stdin oder sowas hab auch schon länger nicht in c programmiert. 

Also das "in" ist ja bei mir ein  BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

und das hat leider keine .available() methode

Kommentar von TeeTier ,

Da du von System.in immer nur ein einziges Zeichen liest, wobei es dir nicht mal auf eine Umkodierung ankommt, kannst du dir sowohl den BufferedReader als auch den InputStreamReader sparen, und mal folgendes versuchen:

import static java.lang.System.*;

...

while (true) {
out.println(Math.floor(Math.random() * 2));

while (in.available()) {
in.read();
}

in.read();
}

Die statischen Imports habe ich jetzt nur benutzt, um das Snippet zu verkürzen. Das kannst du natürlich auch mit lokalen Variablen oder voller Objekt-Auflösung machen, wie du möchtest. :)

Antwort
von Berny96, 33

Versuchs mal mit: 

while(true){ 

System.out.println(Math.floor(Math.random()*2));

in.read();

}
Kommentar von KnusperPudding ,

Das ist anstatt einer Fussgesteuerten Schleife eine Kopfgesteuerte, hat jedoch nichts mit dem Problem zu tun.

Antwort
von xGlumi, 30

Also bei mir läuft alles super (mit deinem Beispielcode)

https://i.gyazo.com/689ba3705564e65380a1a47bc7a540c4.png

MFG xGlumi

Kommentar von KnusperPudding ,

Das Problem tritt auf, sobald man in die Konsole mindestens ein Zeichen eingibt. (ich nehme mal an, dass der Fragesteller ein Leerzeichen eingegeben hat)

Kommentar von xGlumi ,

Dennoch klappt es bei mir

MFG xGlumi

Kommentar von alexG93 ,

also wenn ich nur enter drücke kommen zwei s.o.p

wenn ich ein zeichen und dann enter drück kommen drei s.o.p

Expertenantwort
von KnusperPudding, Community-Experte für Java, 28

Du hast ja eine Fussgesteuerte Endlos-Schleife. 

Mit: in.read() reagiert auf eine Eingabe. D.h. auch bei einem Enter ohne Zeichen wird fortgesetzt. Und dann natürlich Pro eingegebenem Zeichen eben auch und entsprechend reagiert deine Schleife auch.

Sagen wir mal, du gibst Test in die Konsole ein.

So wird die Schleife 5 mal durchlaufen.

1. T 2. e 3. s 4. t 5. Return

Naja, und bei einem Normalen Inputstream weißt du auch nicht so einfach, ob der nun 'Zuende' ist oder nicht. 

Eine Lösung wäre, du verwendest einen BufferedReader, mit dem kannst du dann Einzelne Zeilen Pro Input einlesen, die auf Carriage-Return (Enter-Taste) reagieren. Würde beispielsweise so aussehen:

do {
System.out.println(Math.floor(Math.random() * 2)); new BufferedReader(new InputStreamReader(new BufferedInputStream(System.in))).readLine();
} while (true);
Kommentar von alexG93 ,

funktioniert super

allerdings hab ich mir erhofft dass ich ein pendant zum getch(); in c finde sodass sowas wie Press any key to continue entsteht

Kommentar von KnusperPudding ,

naja, sowas gibt es schon, aber eben nicht für die Konsole. - Das wäre dann z.B. in Swing dann ein Keylistener, bei dem du auf einen Tastendruck reagierst.

Hier wird jedenfalls die eingabe mit Enter als bestätigt gesehen und dann werden die Zeichen 'eingelesen'

Keine passende Antwort gefunden?

Fragen Sie die Community