Wiederkehrende Konsolen-Anzeige mit do-While?!

Wuast

Bekanntes Mitglied
Hallo Experten,
kann mir jemand kurz erklären, warum mein Code den Benutzer nicht wiederkehrend über die Konsole zur Eingabe auffordert? (Ist es keine Rekursion?)

Java:
import java.util.Scanner;

public class EingabeMenue {

    public int menueEingabe() {
       
        boolean menueLaeuft = true;
       
        do {
            System.out.println("Zahl eingeben: ");
            System.out.println(" Zum abbrechen: 0 drücken.");
           
        int eingabe = new java.util.Scanner(System.in).nextInt();
       
        if (eingabe != 0) {
            return eingabe;
        }
        else
            System.out.println("Menü beendet.");
            menueLaeuft = false;
        }
       
        while (menueLaeuft);
       
    return 0;      
    }
   
   
    public class Main{

    public static void main(String[] args) {

    EingabeMenue menue = new EingabeMenue();
    long zahlenEingabe = menue.menueEingabe();
   
   
    System.out.println(zahlenEingabe);
    }
}

Konsole gibt nur folgendes her:

Zahl eingeben:
Zum abbrechen: 0 dr�cken.
123 //(Eingabe)
123 //(Ausgabe)

LG :)
 

httpdigest

Top Contributor
Java:
        if (eingabe != 0) {
            return eingabe; // <-- hier kehrst du aus der Methode zurück zum Aufrufer!
        }
}
Ist es keine Rekursion?
Drei Sachen:
1. das, was du da machst, ist keine Rekursion, es ist eine Schleife oder auch "Iteration" genannt (du brauchst hier aber auch keine Rekursion)
2. du eröffnest immer einen neuen Scanner mit System.in. Das solltest du sein lassen und nur einmal einen Scanner mit System.in öffnen
3. die eigentliche Ursache ist das return eingabe;
 

Wuast

Bekanntes Mitglied
Drei Sachen:
1. das, was du da machst, ist keine Rekursion, es ist eine Schleife oder auch "Iteration" genannt (du brauchst hier aber auch keine Rekursion)
2. du eröffnest immer einen neuen Scanner mit System.in. Das solltest du sein lassen und nur einmal einen Scanner mit System.in öffnen
3. die eigentliche Ursache ist das return eingabe;
Danke für deine Rückmeldung

Aber ich benötige doch einen Rückgabewert.

Wenn ich die Methode auf void setze, kann ich in der main ja nicht die Eingabe aus der Klasse.Methode EingabeMenue.menueLaeuft(); in den int zahlenEingabe packen.

Java:
public class EingabeMenue {

    public void menueEingabe() {
        
        boolean menueLaeuft = true;
        
        Scanner scanner = new Scanner(System.in);
        
        do {
            System.out.println("Zahl eingeben: ");
            System.out.println(" Zum abbrechen: 0 drücken.");
        
            int eingabe = scanner.nextInt();

            if (eingabe == 0)
            System.out.println("Menü beendet.");
            menueLaeuft = false;
        }
        
        while (menueLaeuft);
         
    }
}

public class Main{

    public static void main(String[] args) {
    
    EingabeMenue menue = new EingabeMenue();
    int zahlenEingabe = menue.menueEingabe();    //hier meckert die IDE zurecht, weil ich keinen int zurückgebe
    
    
    System.out.println(zahlenEingabe);
    }
}

lasse ich den Rückgabewert int muss ich ja irgendetwas zurückgeben. Aber was und warum? stehe mal wieder auf dem Schlauch.. :(
 

KonradN

Super-Moderator
Mitarbeiter
Die Frage ist, was Du machen willst und was die Anforderung ist.

Egal, was für eine Zahl eingegeben wird: Du gibst diese zurück:
eingabe != 0 -> return eingabe
eingabe == 0 -> return 0 (nach dem Verlassen der Schleife)

Möchtest Du eine Wiederholung der Eingabe, wenn keine Zahl eingegeben wurde? In dem Fall tritt eine Exception auf: Der Scanner kann keine Zahl einlesen (weil der Benutzer z.B. "hallo" eingegeben hat) und daher wird eine Exception geworfen. Eine InputMissmatchException um genau zu sein.

==> Merke: Bitte immer genau angeben, was aus Deiner Sicht falsch läuft. Was passiert genau? Und dann stellst Du dem gegenüber, was Du gerne haben möchtest. Das vereinfacht die Antworten und man muss nicht raten.

Wenn ich das Problem erkannt habe, dann sind da zwei Dinge zu tun:
a) Die Exception muss gefangen werden. Dies geht mit einem Try / Catch
b) Wenn Du keinen neuen Scanner erstellst (Was nicht gut ist!), dann musst Du die Eingabe noch entfernen. Dazu könnte z.B. nextLine oder next aufgerufen werden. Immer einen neuen Scanner zu erstellen würde hier das Problem aber auch lösen, da die fehlerhafte Eingabe vom alten Scanner aus dem Stream gelesen wurde und in einer Art Cache steckt. Diese Bereinigung wäre damit also gegeben.
 

Neumi5694

Top Contributor
Return beendet immer die aktuelle Methode.
Wenn der Eingabewert außerhalb ausgewertet werden soll, dann muss auch die Schleife nach außen.
Eine Alternative ist, dass du nicht außen auswertest, sondern die Behandlung des Wertes von dieser Methode aus aufrufst. Am Ende läuft das aber auf das gleiche hinaus.

schleife {
eingabe -> auswertung
}
 

Wuast

Bekanntes Mitglied
Möchtest Du eine Wiederholung der Eingabe, wenn keine Zahl eingegeben wurde?[...]

==> Merke: Bitte immer genau angeben, was aus Deiner Sicht falsch läuft. Was passiert genau? Und dann stellst Du dem gegenüber, was Du gerne haben möchtest. Das vereinfacht die Antworten und man muss nicht raten.
Hast recht.
Also man soll über die Konsole immer wieder neu eine Zahl eingeben können. Eigentlich soll es bei der Aufgabe ums Threadden gehen. In einem seperaten Thread soll die eingegebene Zahl daraufhin überprüft werden, ob sie eine Primzahl ist. Soweit bin ich ja jetzt noch nicht, ich wollte zunächst das "Menü" erstellen (mir ist spontan kein besserer Name eingefallen), welches über die Konsole dazu auffordert, eine Zahl einzugeben oder halt das Programm zu beenden. Deswegen die Schleife: Solange der boolean true ist, sollte die Schleife doch weiterlaufen. Und immer wenn eine Zahl eingegeben wurde, soll ein thread im Hintergrund auf Primzahl überprüfen.

b) Wenn Du keinen neuen Scanner erstellst (Was nicht gut ist!), dann musst Du die Eingabe noch entfernen. Dazu könnte z.B. nextLine oder next aufgerufen werden. Immer einen neuen Scanner zu erstellen würde hier das Problem aber auch lösen, da die fehlerhafte Eingabe vom alten Scanner aus dem Stream gelesen wurde und in einer Art Cache steckt. Diese Bereinigung wäre damit also gegeben.
Aber das steht im Gegensatz zu
2. du eröffnest immer einen neuen Scanner mit System.in. Das solltest du sein lassen und nur einmal einen Scanner mit System.in öffnen
oder nicht?
 
Zuletzt bearbeitet:

Neumi5694

Top Contributor
So insgesamt komm ich gedanklich gerade noch nicht weiter, wie ich das vorhaben lösen kann. Mein Gedanke war ja Rekursion (auch wenn ich


die nicht umgesetzt habe), aber scheint ja nicht die Wahl zu sein?!
Nur zum Thema Rekursion. Bei einer Rekursion ruft sich die Methode selbst auf. Das passiert hier nicht und wäre auch in keiner Weise sinnvoll.
 

Wuast

Bekanntes Mitglied
Nur zum Thema Rekursion. Bei einer Rekursion ruft sich die Methode selbst auf. Das passiert hier nicht und wäre auch in keiner Weise sinnvoll.
War mein erster Gedanke mit der Rekursion, aber die Schleife funktioniert ja auch.
Daher korrigiere ich meine vorletzte Antwort nochmal kurz^^.

Also so funktioniert es dann tatsächlich, dass die Schleife weiterläuft. aber die Konsolenausgabe passt noch nicht:
Java:
public class EingabeMenue {

    public int menueEingabe() {
      
        boolean menueLaeuft = true;
      
        Scanner scanner = new Scanner(System.in);
        int eingabe;
      
        do {
            System.out.println("Zahl eingeben: ");
            System.out.println(" Zum abbrechen: 0 drücken.");
      
            eingabe = scanner.nextInt();
            System.out.println();
            }
        while (menueLaeuft);
      
        if (eingabe != 0)
            return eingabe;
      
        if (eingabe == 0)
            System.out.println("Menü beendet.");
            menueLaeuft = false;
            return 0;
      
public class Main{

    public static void main(String[] args) {
   
    EingabeMenue menue = new EingabeMenue();
    System.out.println(menue.menueEingabe());
   
    int eingabe = menue.menueEingabe();
    System.out.println(eingabe);
    }
}

    }

Konsolenausgabe:
Zahl eingeben:
Zum abbrechen: 0 dr�cken.
123

Zahl eingeben:
Zum abbrechen: 0 dr�cken.
0

Zahl eingeben:
Zum abbrechen: 0 dr�cken.

usw.

Ich kann es drehen und wenden wie ich will: Entweder endet die Schleife, oder ich habe nicht den eingabe-Int als Rückgabewert, um ihn in einer Variablen in der Main zu speichern. :D


Jetzt hoffe ich auch auf Rückmeldungen zu den unterschiedlichen Ansichten beim Scanner bzw. eine kurze Erläuterung :)
 
Zuletzt bearbeitet:

Neumi5694

Top Contributor
Jetzt hoffe ich aber noch auf Rückmeldungen zu den unterschiedlichen Ansichten beim Scanner bzw. eine kurze Erläuterung :)
Beim Scanner halt ich mich raus, ich arbeite immer mit UIs oder Kommandozeilenparametern. Eingaben per Prompt in der Kommandozeile hab ich seit Pascal nicht mehr gemacht (ok TurboC könnte man noch zählen, da haben wir als Übung ein serielles Chat-Programm im DOS-Fenster geschrieben).

Ist es schädlich, mehrer zu haben? Ich denke nicht, außer der eine liest dem anderen was weg. Einer pro Programm sollte reichen. Pass nur auf, dass du ihn nicht schließt.
Den Post hatte ich so verstanden, dass man vor Verwendung erst mal auslesen sollte, damit schon vorher getätigte Eingaben nicht mehr im Stream sind.


Dass deine Schleife angeblich funktioniert, fasziniert mich echt ...
Bist du mal durchgegangen, was da eigentlich passiert?

Java:
  do {
            System.out.println("Zahl eingeben: ");
            System.out.println(" Zum abbrechen: 0 drücken.");
  
            eingabe = scanner.nextInt();
            System.out.println();
            }
        while (menueLaeuft);

Wann soll das denn abgebrochen werden? menuLaeuft wird in der Schleife nie verändert, es behält immer seinen Wert bei. Das ist eine Endlosschleife, wird auch nicht bei 0 beendet.

Code:
boolean menuLaeuft; //setz ich mal absichtlich nicht, damit es zwingend in der Schleife gesetzt werden muss
do {
  int eingabe = ...;
  menuLaeuft = eingabe != 0;
  if (menuLaeuft) { //angenommen, du willst bei 0 nichts machen
    tuWasMit(eingabe);
  }
} while (menuLaeuft);
und das OHNE return, sonst würde die Methode ja beendet.

Diese Struktur musst du beibehalten, sonst wird das nix. Wenn du irgendwo ein Return mit der Eingabe hast, dann muss die Schleife in einer anderen Methode weiter außen sein - so wie vorher schon beschrieben.

Dein Code ist ziemlich chaotisch
1. Endlosschleife
falles es dann mal weitergehen würde:
2. Rückgabe des letzten eingegebenen Wertes
3. Auswerten des letzten eingegebenen Wertes

Alle anderen Werte würden ignoriert, falls die Endlosschleife dein Vorhaben nicht eh schon zunichte machen würde.
 

Wuast

Bekanntes Mitglied
Dass deine Schleife angeblich funktioniert, fasziniert mich echt ...
Bist du mal durchgegangen, was da eigentlich passiert?

Java:
  do {
            System.out.println("Zahl eingeben: ");
            System.out.println(" Zum abbrechen: 0 drücken.");
 
            eingabe = scanner.nextInt();
            System.out.println();
            }
        while (menueLaeuft);

Wann soll das denn abgebrochen werden? menuLaeuft wird in der Schleife nie verändert, es behält immer seinen Wert bei. Das ist eine Endlosschleife, wird auch nicht bei 0 beendet.

Code:
boolean menuLaeuft; //setz ich mal absichtlich nicht, damit es zwingend in der Schleife gesetzt werden muss
do {
  int eingabe = ...;
  menuLaeuft = eingabe != 0;
  if (menuLaeuft) { //angenommen, du willst bei 0 nichts machen
    tuWasMit(eingabe);
  }
} while (menuLaeuft);
und das OHNE return, sonst würde die Methode ja beendet.

Diese Struktur musst du beibehalten, sonst wird das nix. Wenn du irgendwo ein Return mit der Eingabe hast, dann muss die Schleife in einer anderen Methode weiter außen sein - so wie vorher schon beschrieben.

Dein Code ist ziemlich chaotisch
1. Endlosschleife
falles es dann mal weitergehen würde:
2. Rückgabe des letzten eingegebenen Wertes
3. Auswerten des letzten eingegebenen Wertes

Alle anderen Werte würden ignoriert, falls die Endlosschleife dein Vorhaben nicht eh schon zunichte machen würde.
Hat auch nicht funktioniert... :D

Was hälst du denn davon? Mein Problem ist dann aber dabei, dass ich aus der Schleife ja nicht herauskomme, um die getEingabe "zu verwerten".

Java:
import java.util.Scanner;

public class EingabeMenue {

    private boolean menueLaeuft = true;
    private int eingabe;
    
        
        public void menueEingabe() {

        do {
        
        System.out.println("Zum abbrechen: 0 drücken.");
        System.out.println("Zu prüfende Zahl eingeben: ");
            
        eingabe = new Scanner(System.in).nextInt();
        
        if (eingabe == 0) {
            menueLaeuft = false; 
            System.out.println("Beendet!");
            break;
            }
        else {
            getEingabe();
            System.out.println(getEingabe() + " eingegeben. Zahl wird geprüft.");
            }
        }
        while (menueLaeuft); 
        
    }
        
    public int getEingabe() {
            return eingabe;
    }    
    
}

Code:
public class Main{

    public static void main(String[] args) {
    
    EingabeMenue menue = new EingabeMenue();
    menue.menueEingabe();
    
    System.out.println(menue.getEingabe()); //Rückfrage: *
    }
}
* An der Stelle kurz die Rückfrage: Habe ich es richtig verstanden, dass diese Ausgabe nicht kommt, weil die Schleife nicht beendet wird? (Heißt, entweder das Programm kommt dort nicht an weil die Do-While endlos ist, ODER die eingabe ist leer weil die Do-While die getEingabe() nicht aufruft und deswegen kein Wert in der eingabe vorhanden ist!?
Nur was sich mir partou nicht erschließt: Wie kann ich denn jetzt den Wert aus dem Scanner verwerten, ohne die Schleife zu beenden?
Habe ich meine Verwirrung verständlich beschrieben? :/
 

Wuast

Bekanntes Mitglied
Ich ergänze nochmal meinen Code zum Threadding, damit hoffentlich klar ist, wie ich das eigentlich beabsichtige, sobald ich die getEingabe()-Geschichte hinbekommen habe:
Java:
public class Main{

    public static void main(String[] args) {
    
    EingabeMenue menue = new EingabeMenue();
    menue.menueEingabe();
    
    int eingabe = menue.getEingabe();    //geht nicht, da die Schleife aus menue.menueEingabe() nicht beendet wird!
    
    System.out.println(eingabe);        //geht nicht, da die Schleife aus menue.menueEingabe() nicht beendet wird!
    
    ThreadFuerPrimzahlenUeberpruefung primPrüf = new ThreadFuerPrimzahlenUeberpruefung();
    Thread primzahlenUeberpruefung = new Thread(primPrüf);
    primzahlenUeberpruefung.start();
    }
}


public class ThreadFuerPrimzahlenUeberpruefung implements Runnable{

    EingabeMenue menue = new EingabeMenue();
    int eingabe = menue.getEingabe();

    @Override
    public void run() {
    
        if (eingabe % 2 == 0) {
            System.out.println("Die Zahl " + eingabe + " ist keine Primzahl.");
        }
    }
}


So, danke vorab für deine/eure Mühen.
 

Neumi5694

Top Contributor
So oder so muss er eine Abbruchbedingung prüfen und das macht er nicht.

Und was die Lesbarkeit angeht ... nein. Mit einem break musst du im Code erst mal suchen, wo deine Schleife beendet wurde. Bei While oder Do-While bist du sicher, dass das Ende jeweils erreicht wird. Breaks setz ich auch ein, aber lesbarer machen die den Code gewiss nicht,

Nur was sich mir partou nicht erschließt: Wie kann ich denn jetzt den Wert aus dem Scanner verwerten, ohne die Schleife zu beenden?
Habe ich meine Verwirrung verständlich beschrieben? :/
Indem du das in der Schleife machst. Niemand hindert dich daran, den Wert an eine andere Methode weiterzugeben. Siehe mein Code.

Du hast das Prinzip eines Rückgabewerts nicht verstanden. Wenn eine Methode einen Wert liefert, dann war's das. Dann ist die Methode beendet.
Wenn sie öfters einen Wert liefern soll, dann muss diese Methode öfters aufgerufen werden. Stichwort: Schleife AUSSEN DRUM RUM.
Du kannst allerdings auch eine Liste von Werten liefern.
Java:
public List<Integer> aMethod() {
    List<Integer> myList = new ArrayList<>();
    while (runLoop) {
        int aValue = ...;
        myList.add(aValue);
        //jetzt irgendwann auch mal abbrechen, also runLoop auf false setzen.
    }
    return myList;
}
 

KonradN

Super-Moderator
Mitarbeiter
Also meine Aussage war evtl. missverständlich:
Wenn Du keinen neuen Scanner erstellst (Was nicht gut ist!)
Das "nicht gut ist" bezog sich auf das neuen Scanner erstellen.

Um es ganz deutlich zu sagen: Wenn Du mit einem Scanner auf System.in arbeiten willst, dann solltest Du genau ein einziges Mal einen erzeugen und diesen dann immer verwenden.

Also ganz genau das, was auch @httpdigest gesagt hat - ich habe dazu nur schon ausgeführt, wie man damit dann umgehen müsste (so Du die Exception fangen willst und weiter arbeiten willst).

Ist es schädlich, mehrer zu haben? Ich denke nicht, außer der eine liest dem anderen was weg. Einer pro Programm sollte reichen. Pass nur auf, dass du ihn nicht schließt.
Das hier immer davon abgeraten wird, hat natürlich einen Grund. Den möchte ich einfach einmal etwas ausführen.

Scanner liest Daten vom Stream und speichert diesen intern in der Instanz. Das führt bei einem fehlerhaften Token dazu, dass man bei dem neuen Scanner das fehlerhafte Token nicht mehr hat. Das funktioniert auch bei den einzelnen Eingaben sehr gut.

Die Betriebssysteme erlauben aber z.B., dass man dem Programm eine Datei als Eingabe gibt. Oder der Scanner wird dann auf einer anderen Quelle als System.in erstellt. Und da wird es dann kritisch, denn da ist es ja möglich, dass mehr gelesen wird.
Bei der Eingabe ist nach der Enter Teste erst einmal Schluss. Es ist also klar: Es wurde nur bis zu dem Return gelesen. Aber wenn die ganze Eingabe auf einmal kommt?

Das Verhalten, wie viel ganz genau gelesen wird, ist aus meiner Sicht nicht konkret beschrieben und damit nicht Bestandteil des Interfaces. Daher sollte man keinen Code schreiben, der auf einer konkreten Implementation basiert. Daher: ja, für die ersten einfachen Schritte ist es von der Funktion noch ok.

Daher ist es mehr ein Ratschlag, um nicht später in irgendwelche Probleme zu kommen und um nicht am Anfang Patterns zu lernen.

Aber @Neumi5694 hat das auch schon recht gut gesagt: Damit arbeitet man später meist nicht mehr, so dass diese Ausführungen für die Meisten eh uninteressant sein dürfte. Aber vielleicht war es ja interessant, da einmal zu erfahren, warum davon abgeraten wird (zumindest aus meiner Sicht).
 

KonradN

Super-Moderator
Mitarbeiter
Deine Schleife macht so erst einmal keinen Sinn. Und aus Deinem Code kann ich nicht ableiten, was Du genau willst.

Der Aufruf von getEingabe() innerhalb der Schleife macht absolut nichts. getEingabe gibt die letzte Eingabe zurück, damit machst Du aber nichts und du hättest es ja auch direkt schon in der Variablen eingabe.

Die Implementation sieht etwas danach aus, dass Du da eine Art Programmführungs-Schleife haben willst. Das wäre dann so eine typische Schleife, bei 0 beendet sich dann das Programm. Und gültige Eingaben führen zu Aktionen. Sprich: In dem else müsstest Du dann irgendwas machen.

Aber der Aufruf sieht dann nur nach einer einfachen Eingaberoutine aus. Ohne Exceptions abzufangen wäre dies dann nur etwas wie:

Java:
import java.util.Scanner;

public class EingabeMenue {

        public int menueEingabe() {
            System.out.println("Zum abbrechen: 0 drücken.");
            System.out.println("Zu prüfende Zahl eingeben: ");
            
            return new Scanner(System.in).nextInt();       
    }
}
Was dann erfolgt, ist dann natürlich in der Routine - Du rufst menuEingabe auf und bekommst die Auswahl zurück. Dann kannst Du die Zahl auswerten.

Also etwas wie:
Code:
    public static void main(String[] args) {
    
        EingabeMenue menue = new EingabeMenue();
        do {
            int eingabe = menue.menueEingabe();
            
            if (eingabe == 0) {
                System.out.println("Bye bye ...");
                break;
            }
            
            System.out.println(eingabe);
    
            ThreadFuerPrimzahlenUeberpruefung primPrüf = new ThreadFuerPrimzahlenUeberpruefung();
            Thread primzahlenUeberpruefung = new Thread(primPrüf);
            primzahlenUeberpruefung.start();
        }
    }
}
 

dünner

Mitglied
Und was die Lesbarkeit angeht ... nein. Mit einem break musst du im Code erst mal suchen, wo deine Schleife beendet wurde. Bei While oder Do-While bist du sicher, dass das Ende jeweils erreicht wird. Breaks setz ich auch ein, aber lesbarer machen die den Code gewiss nicht,
Das ist idiotisch, weil ein einfaches break; an richtiger Stelle übersichtlicher ist als ein Do-While. Das lässt sich auch nicht schönreden.
 

KonradN

Super-Moderator
Mitarbeiter
Das ist idiotisch, weil ein einfaches break; an richtiger Stelle übersichtlicher ist als ein Do-While. Das lässt sich auch nicht schönreden.
Andere Meinungen sollte man nicht direkt als idiotisch abstempeln. Das sind alles legitime Sichtweisen.

Ich gebe @Neumi5694 in diesem Punkt durchaus Recht: Die Kernidee bei der Schleifenbedingung ist nun einmal, dass man dort erkennen kann, wann die Schleife verlassen wird. Dies in der Schleife mit einem break zu implementieren widerspricht somit erst einmal der generellen "Schleifen-Philosophie". So ist es üblich, dass man bei der Schleife auf die Bedingung schaut, wenn man wissen will, wann diese beendet wird.

So lange die Methoden (bzw. hier die Schleife) entsprechend kurz und übersichtlich gehalten wird, ist dies aber erst einmal unproblematisch. Das ist aber eine wichtige Voraussetzung für dieses Vorgehen. Daher würde ich einen Tipp wie in #12 nie aussprechen. Gerade auf einem Anfänger-Niveau (Sorry @Wuast - das ist keine Wertung, ich hoffe, du weisst das!) halte ich dies für fatal.

Das gilt übrigens 1:1 auch für return Anweisungen in einer Methode. Wenn man diese nicht klein und übersichtlich hält, dann sehe ich das ähnlich problematisch. Das wäre ja die Konsequenz bei einer Umstellung: Man hat die Schleife in einer Methode und man geht dann einfach mit return raus.

Dass dieses Vorgehen durchaus nicht unkritisch ist, sieht man ansonsten auch bei Refactorings:
Der Teil, der das break enthält, wird in eine Methode verschoben -> break geht so nicht mehr.
==> Refactorings werden durch unsauberen Code erschwert und so stufe ich diese break Variante auch ein.

Und ja - ich erinnere mich gut, dass Du break und continue liebst ... selbst verschachtelte Schleifen mit Labels um dann break und continue mit Label zu nutzen. Das will ich Dir auch nicht ausreden - also da nicht falsch verstehen. Aber ich habe da nun einmal eine andere Sicht drauf und nur die habe ich hier mitgeteilt.
 

Neumi5694

Top Contributor
Das ist idiotisch, weil ein einfaches break; an richtiger Stelle übersichtlicher ist als ein Do-While. Das lässt sich auch nicht schönreden.
Braucht man nichts schönreden. Beim while siehst du, wann Ende ist. Beim Break musst du die "richtige Stelle" erst mal finden.
Ich zweifle nicht an, dass es mit breaks funktioniert, ich verwende sie selbst ja auch, vor allem bei Suchen in Interables. Aber lesbarer wird der Code dadurch ganz gewiss nicht. Ohne Label oder Dokumentation der Zeile ... nein danke. Dann doch lieber eine Lesbare Bedingung im Header der Schleife (oder im Fußbereich, je nachdem, ob man mindestens einmal rein will oder nicht).
Du magst das als idiotisch empfinden, aber ich liebe es, meinen Code nach mehreren Jahren noch zu verstehen.
 

Wuast

Bekanntes Mitglied
Indem du das in der Schleife machst. Niemand hindert dich daran, den Wert an eine andere Methode weiterzugeben. Siehe mein Code.
ach jetzt weiß ich was du meinst, habe das falsch verstanden. Also grundsätzlich etwas in dieser Art?
Java:
if (eingabe == 0) {
            menueLaeuft = false;
            System.out.println("Beendet!");
            break;
            }
        else {
            nimmEingabewertEntgegen(eingabe);
            System.out.println(getEingabe() + " eingegeben. Zahl wird geprüft.");
            }
        }
        while (menueLaeuft);
    }
       //folgendes ist gemeint, sollte eigentlich [B]FETT[/B] sein
    [B]public int nimmEingabewertEntgegen(int eingabe) {
        this.eingabe = eingabe;
        return eingabe;[/B]
    }
Du hast das Prinzip eines Rückgabewerts nicht verstanden. Wenn eine Methode einen Wert liefert, dann war's das. Dann ist die Methode beendet.
Wenn sie öfters einen Wert liefern soll, dann muss diese Methode öfters aufgerufen werden. Stichwort: Schleife AUSSEN DRUM RUM.
Außen drum rum um die Methode? Also die Methode in der Schleife aufrufen, meinst du das damit?Das wäre dann ja das, was auch Konrad vorschlägt, korrekt erfasst?
Also etwas wie:
Code:
    public static void main(String[] args) {
  
        EingabeMenue menue = new EingabeMenue();
        do {
            int eingabe = menue.menueEingabe();
          
            if (eingabe == 0) {
                System.out.println("Bye bye ...");
                break;
            }
          
            System.out.println(eingabe);
  
            ThreadFuerPrimzahlenUeberpruefung primPrüf = new ThreadFuerPrimzahlenUeberpruefung();
            Thread primzahlenUeberpruefung = new Thread(primPrüf);
            primzahlenUeberpruefung.start();
        }
    }
}

Das versuche ich damit nochmal :D (bzw. ich habe ja quasi eine Lösung jetzt) Kann ja wohl nicht sein. Aber das der Rückgabewert die Methode beendet, war mir tatsächlich nicht klar. Wieder was gelernt!

Gerade auf einem Anfänger-Niveau (Sorry @Wuast - das ist keine Wertung, ich hoffe, du weisst das!) halte ich dies für fatal.
Der Rat der Fliesentischbesitzer ist empört! Spaß beiseite, das weiß ich natürlich. Sonst würde ich hier nicht diese Art von Fragen stellen.

Also vielen Dank an alle Rückmeldungen an dieser Stelle. Sollte ich nochmal stolpern bin ich so frech und frage hier nochmal nach! Habt mir sehr geholfen.
 

Wuast

Bekanntes Mitglied
aus Deinem Code kann ich nicht ableiten, was Du genau willst.

Der Aufruf von getEingabe() innerhalb der Schleife macht absolut nichts. getEingabe gibt die letzte Eingabe zurück, damit machst Du aber nichts und du hättest es ja auch direkt schon in der Variablen eingabe.

Die Implementation sieht etwas danach aus, dass Du da eine Art Programmführungs-Schleife haben willst. Das wäre dann so eine typische Schleife, bei 0 beendet sich dann das Programm. Und gültige Eingaben führen zu Aktionen. Sprich: In dem else müsstest Du dann irgendwas machen.
Was ich will: Über die Konsole soll eine Zahl eingegeben werden. Ein anderer thread soll parallel dazu laufen und prüfen, ob es sich um eine Primzahl handelt.

(sorry für die Doppelantwort, konnte ich nicht mehr über das Bearbeiten in die vorherige einfügen)
 

Wuast

Bekanntes Mitglied
Okay, jetzt tut das Programm, was es soll. Zwecks Eleganz sollte die do-While in eine eigene Klasse ausgelagert werden, habe ich das hier im Rahmen meiner anderen Nachfragen richtig verstanden?
Ansonsten ist das soweit i.O.? (falls nochmal jemand drüber schauen möchte). Falls es noch Tipps oder Hinweise (auch zum Threadden) gibt freue ich mich natürlich sehr.

Java:
public class Main{

    public static void main(String[] args) {
    
    //thread über runnable-Interface:
    ThreadFuerPrimzahlenUeberpruefung primPruef = new ThreadFuerPrimzahlenUeberpruefung();
    Thread primzahlenUeberpruefung = new Thread(primPruef);
    //primzahlenUeberpruefung.start(); erfolgt erst in der do-while-Schleife
    
    boolean schleifeLaeuft = true;
        
    EingabeMenue zahlenEingabe = new EingabeMenue();
    
    do {
        int eingabe = zahlenEingabe.zahlenEingabe();
        
        if (eingabe == 0) {
            System.out.println("Beendet.");
            schleifeLaeuft = false;
        }
        else {
            System.out.println("Die Zahl " + eingabe + " wird geprueft.");
            try {
                Thread.sleep(1000);        //vermutlich unnötig aber fand ich witzig
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
            primPruef.empfangeEingabe(eingabe);
            primzahlenUeberpruefung.start();
            }
            catch(Exception e) {
                System.out.println("Fehler bei der Ueberpruefung.");
            }
            try {
                Thread.sleep(1000);        //für die Funktion unnötig, aber die Darstellung ist dann flüssiger, weil der thread primPruef dann erst seine Antwort liefert
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }
    while (schleifeLaeuft);
        
    }
}

public class ThreadFuerPrimzahlenUeberpruefung implements Runnable{
    
    private int eingabe;

    public int empfangeEingabe(int eingabe) {
        this.eingabe = eingabe;
        return eingabe;
    }
    
    @Override
    public void run() {

        if (eingabe % 2 == 0) {
            System.out.println("Die Zahl " + eingabe + " ist keine Primzahl.");
        }   
        else {
            System.out.println("Die Zahl " + eingabe + " ist eine Primzahl.");
        }
        
    }
}
 

Neumi5694

Top Contributor
Wie Caesar sagte: ad assem fluens - Der Groschen ist gefallen :)
Wenn du eine Methode hast, die einen Rückgabewert liefert, du aber mehrere brauchst, dann brauchst du außerhalb mehrere Aufrufe, etwa in Form einer Schleife.
Wenn sie hingegen eine Liste von Ergebnissen liefern kann, dann befüllst du die Liste natürlich in der Methode, z.B. innerhalb einer Schleife, die dann ebenfalls innerhalb der Methode zu finden ist.

Ein einfacher Algorithmus (und viel mehr hast du hier ja nicht) muss nur selten in verschiedene Klassen aufgeteilt werden, Sinn ergibt das für in sich abgeschlossene Teilberechnungen. Aber irgendwas in eine andere Klasse zu schieben, nur damit's dort ist, ist wenig sinnvoll.
Ähnliches gilt für das Aufspalten in diverse Methoden.


Deine Logik hat einen gewissen Denkfehler. Wenn du Zahlen im Hintergrund in einem eigenen Thread prüfen lassen willst, warum schickst du den Thread des Hauptprogramms dann schlafen? Lass den Benutzer doch weiter eingeben und starte dann weitere Threads.
Wenn du im Hauptprogramm das Ergebnis haben willst, ergeben Hintergrundthreads eigentlich eh keinen Sinn, aber es ist halt eine Übungsaufgabe.

Deine Thread.sleep() sind tatsächlich unnötig und auch kontraproduktiv(du weißt ja nicht, wie lange der Thread wirklich braucht).
Wenn du auf das Ende eines Threads warten willst, dann machst du das mit threadvariable.join();

Man kann einen Thread übrigens nur einmal starten, danach muss er neu erstellt werden.

Aufteilen in Thread und Runnable ist unnötig. Man kann ein Runnable an einen Thread übergeben, aber eine davon ableitende Klasse hat eh eine passende Methode.

Wenn du das Ganze tatsächlich im Hintergrund machen willst ohne auf den Thread zu warten, dann würde ich eine Thread-Klasse in dieser Art vorschlagen:
Java:
MyThread extends Thread {
    MyThread(int numberToTest, Consumer<Integer> onSuccess, Consumer<Integer> onFailure) {
        ...;//Eingabeparameter übernehmen
    }
    public void run() {
        boolean success = ...;//prüfung
        if (success) {
            if (onSuccess != null) {//man weiß ja nie
                onSuccess.accept(numberToTest);
            }
        } else {
            if (onSuccess != null) {
                onFailure.accept(numberToTest);
            }
        }
    }
    private final int numberToTest;
    private final Consumer<Integer> onSuccess;
    private final Consumer<Integer> onFailure;
}


//Aufruf mit:
class MyClass {
    public static void main(String... args) {
        do {
            eingabe = ...;
            //Thread erstellen und starten.
            var testThread = new MyThread(eingabe, this::handlePrime, this::handleNonPrime);
            testThread.start();
            //wenn man jetzt - aus welchen Gründen auch immer - darauf warten will, dann
            try {
                testThread.join();
            } catch (InterruptedException e) {
                //..;
            }
       
            //Eine andere Art, um ihn aufzurufen, ohne eigene Methoden.
            var alternativeThread = new MyThread(eingabe, i -> System.out.printf("%d is a prime%n", i), i -> System.out.printf("%d is not a prime%n", i));
       
        } while(...);
    }
    private void handlePrime(int number) {//man weiß ja nie
        System.out.printf("%d is a prime%n", number);
    }
    private void handleNonPrime(int number) {
        System.out.printf("%d is not a prime%n", number);
    }
}
edit: Hab das Ganze mal schnell in der Webpage runtergeklopft. Falsche Variablennamen usw. sind möglich.

ps: Anstatt 2 Consumern kannst du z.B. auch einen BiConsumer verwenden, mit int und boolean als parametern, im Boolean-Parameter würde dann stehen, ob es sich um eine Primzahl handelt. Auch muss sich die Behandlung nicht auf eine Bildschirmausgabe beschränken, du könntest die gefundene Primzahl z.B. einer Liste von Primzahlen hinzufügen. Du hast da viele Möglichkeiten, eine "beste" gibt es nicht.
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Ansonsten ist das soweit i.O.?
Deine Lösung ist nicht ok. Du erzeugst nur eine Thread Instanz. Ein Thread kann aber nur ein mal gestartet werden:
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

Daher müsstest Du also auch in der Schleife den Thread erzeugen.

Dann ist es so, dass Du nicht zwingend eine eigene Klasse brauchst für Runnable. Da dies ein funktionales Interface ist, reicht da eine Methode aus. Das kann sowohl eine Methodenreferenz oder ein Lambda Ausdruck sein.

Dein Code könnte man also verändern hin zu:
Java:
package de.kneitzel;

public class Main{

    public static void main(String[] args) {

        boolean schleifeLaeuft = true;

        do {
            int eingabe = ...;

            if (eingabe == 0) {
                System.out.println("Beendet.");
                schleifeLaeuft = false;
            }
            else {
                System.out.println("Die Zahl " + eingabe + " wird geprueft.");
                Thread primzahlThread = new Thread(() -> pruefePrimzahl(eingabe));
                primzahlThread.start();
            }
        }
        while (schleifeLaeuft);
    }
   
    public static void pruefePrimzahl(int zahl) {
        if (zahl % 2 == 0) {
            System.out.println("Die Zahl " + zahl + " ist keine Primzahl.");
        }
        else {
            System.out.println("Die Zahl " + zahl + " ist eine Primzahl.");
        }
    }
}

Die Thread.sleep habe ich natürlich auch raus genommen, die Primzahl-Berechnung habe ich nicht angepasst.

Und hier ist dann auch erkennbar, wieso denn die Meinung geäußert wurde, dass ein break lesbarer sein könnte. Damit würde man sich das else sparen. Aber schreiben wir es noch einmal etwas um:

Java:
public class Main{
    public static final int QUIT_NUMBER = 0;
   
    public static void main(String[] args) {

        int eingabe;
       
        do {
            eingabe = ...;

            if (eingabe != QUIT_NUMBER) {
                System.out.println("Die Zahl " + eingabe + " wird geprueft.");
                Thread primzahlThread = new Thread(() -> pruefePrimzahl(eingabe));
                primzahlThread.start();
            }
        } while (eingabe != QUIT_NUMBER);

        System.out.println("Beendet.");
    }

    public static void pruefePrimzahl(int zahl) {
        if (zahl % 2 == 0) {
            System.out.println("Die Zahl " + zahl + " ist keine Primzahl.");
        }
        else {
            System.out.println("Die Zahl " + zahl + " ist eine Primzahl.");
        }
    }
}

Und schon ist die Schleife etwas sauberer. Und die magic number ist verschwunden. Sinn ist auch direkt erkennbar: Wenn man sich überlegt, dass man generell -1 statt 0 verwenden wollte, dann müsste man dies an mehreren Stellen ändern. Da ist leicht eine Stelle zu wenig oder zu viel geändert. Daher der Weg mit der Konstanten.
 

Neumi5694

Top Contributor
Note: Ein Kommentar im Quelltext steht an der falschen Stelle. Anstatt bei der Methode handlePrime(int) zu stehen, sollte er beim null-Test der Consumer stehen.
 

Wuast

Bekanntes Mitglied
Massig Infos, nochmal vielen Dank. Mit dem meisten kann ich viel anfangen :D

Kurz zum Sleep: Der erste ist völlig nutzlos, fand es nur witzig (war ja mein "erster" thread). Aber das mit dem join ist gut. Warum darauf warten? Einfach, damit die Ausgabe in der Konsole in der richtigen Reihenfolge kommt. Weil sonst ist die Schleife schon wieder beim Sysout und liefert dann die Primzahlüberprüfung dazwischen.

Das mit den Konstanten was Konrad erwähnt finde ich auch interessant. Habe ich bisher so noch nicht (bewusst) als Tipp bekommen. Aber ich denke, sowas kommt mit der Erfahrung?!

Wenn du das Ganze tatsächlich im Hintergrund machen willst ohne auf den Thread zu warten, dann würde ich eine Thread-Klasse in dieser Art vorschlagen:
[...]
Aber wäre das nicht wieder verkompliziert (zumidest hier ganz konkret)? Oder was meinst du? Die Art zu threadden habe ich so aus meinem Studienbrief und YT-Videos. Da hieß es, entweder über die Klasse Thread, oder über das Interface Runnable und letzteres wäre die gängige Praxis. Also bezogen auf meinen Code würde ich dann was verändern müssen, wenn es über Runnable laufen sollte?
 

KonradN

Super-Moderator
Mitarbeiter
Aber wäre das nicht wieder verkompliziert (zumidest hier ganz konkret)?
Ja und nein :)

Wenn Du nur eine solche abgeschlossene Aufgabe hast, dann ist es natürlich komplizierter. Da ginge eine einfache Lösung, wie ich diese gezeigt habe.

Aber es gibt viele Dinge, die hier mit hinein spielen (Und dich auch zusammen hängen):
  • Trennung von Verantwortlichkeiten. Der Code hat die Aufgabe, eine Zahl zu prüfen. Und da dies dauern kann, soll dies im Hintergrund passieren. Was mit dem Ergebnis passieren soll ist nicht Aufgabe des Codes! Also keine Ausgabe! Das ist bei mir Vermengt.
  • Man will ja Code wieder verwenden können. Dazu ist es notwendig, es in einzelne, gut durchdachte Teile, zu bauen. Das ist sehr wichtig und da ist @Neumi5694 auch noch nicht weit genug gegangen: Die Berechnung der Primzahl müsste z.B. von der Thread-Logik getrennt werden. Und dann gibt es noch ein paar Pattern, mit denen man da seht gut was tolles aufbauen kann. Das kann extrem weit gehen und den vollen Weg geht man so nicht! Die Regeln widersprechen sich etwas dabei, denn es gibt auch die Regel: YAGNI - You aint gonna need it. Du wirst es nicht brauchen. Man macht also nur Dinge, die man wirklich braucht.
  • Etwas separat aufgeführt: Eine wichtige Trennung ist in der Praxis die Trennung zwischen Ausgabe und Berechnung. Das vermengt man (in der Regel) nicht. Und das ist die wichtige Trennung bei @Neumi5694 (aus meiner Sicht) Das ist also etwas, das man in der Praxis auch wirklich findet. Und zwar schon bei kleineren Programmen. Diese Notwendigkeit kommt eigentlich immer durch die Anforderungen, denn das sind zwei Anforderungen (oder besser Tasks - es mag eine Anforderung sein, aber man teilt es direkt in zwei Tasks): a) Du willst eine Zahl prüfen können, ob dies eine Primzahl ist. b) Du willst das Ergebnis angezeigt bekommen.
  • Loose Kopplung. Du willst keine harten Abhängigkeiten. Das ist ein Grund, warum teilweise viel mit Interfaces gearbeitet wird (Dann hast Du ein Interface das diese Berechnung beschreibt und eine konkrete Implementierung. Die konkrete Implementierung kann dann leicht getauscht werden.) Und auch anders herum: Die Berechnung der Primzahl hat keine harte Abhängigkeit dazu, wer oder was mit dem Ergebnis etwas macht. Das kann jeder sein, der sich dafür Interessiert (und der das Ergebnis "konsumiert" -> Consumer Interface).

Daher ist die Lösung von @Neumi5694 schon extrem gut. Meiner Meinung nach kommen wir an das YAGNI heran. Aber es ist super, dass er es so gezeigt hat. Von mir gab es da für Dich nur eine etwas vereinfachte Lösung weil ich dachte, dass die ggf. für Dich einfacher zu verstehen ist.

Das mit den Konstanten was Konrad erwähnt finde ich auch interessant. Habe ich bisher so noch nicht (bewusst) als Tipp bekommen. Aber ich denke, sowas kommt mit der Erfahrung?!
Das ist Erfahrung aber auch einfach das, was man als "Clean Code" bezeichnet. Da gibt es recht viele Hinweise, die man befolgen sollte und mit der Zeit geht da dann vieles in Fleisch und Blut über.

Wie alles, ist es eine praktische Angelegenheit und die bekommt man mit Übung. Wenn Du sowas vertiefen willst, dann wäre da z.B. https://clean-code-developer.de - die haben aus meiner Sicht ein gutes Stufenprogramm, dass einen nach und nach dahin führt. Das ist etwas, das ich z.B. unseren Junioren auch immer nahe lege (Ich mache da regelmäßig kurze Einführungen zu Clean Code, Unit Tests, TDD, agiles Arbeiten, ... für Duale Studenten, die ich betreuen darf).
Es gibt da aber auch sehr viele Bücher (Robert C Martin alias Uncle Bob mit seinem Putz-Fetisch: Alles muss clean sein: Clean Code, Clean Architecture, Clean Coder, ...)

Aber etwas in die Richtung gehen dann auch Bücher wie: "Entwurfsmuster von Kopf bis Fuß" und "Effective Java" die dann auch Rezepte an die Hand geben (Entwurfmuster geben sowas wie Praktiken, wie Code strukturiert werden kann und Effective Java gibt Best Practices speziell für Java an die Hand).

Also ein sehr großes. weites Feld. Und das verändert sich auch. Daher ist ein Austausch mit Anderen wichtig ebenso wie das Ausblick nach neuen Konzepten und Ideen - um dann für sich einen möglichst guten Weg zu finden.

Kurz zum Sleep: Der erste ist völlig nutzlos, fand es nur witzig (war ja mein "erster" thread). Aber das mit dem join ist gut. Warum darauf warten? Einfach, damit die Ausgabe in der Konsole in der richtigen Reihenfolge kommt. Weil sonst ist die Schleife schon wieder beim Sysout und liefert dann die Primzahlüberprüfung dazwischen.

Wenn Du warten willst, bis es fertig ist, dann nutz keinen Thread. Der Thread ist ja für die Nebenläufigkeit: Du willst im Hauptthread weiter Arbeiten (und hier konkret: weitere Eingaben abfragen). Das Verhalten, das Du hier verhindern willst, ist also doch explizit durch den Ansatz gefordert. Wenn Du das nicht willst, dann hast Du keinen Thread sondern einfach nur einen Aufruf isPrime(input) in einem if mit eine Ausgabe für beide Fälle. Da ist dann nirgends ein Thread oder Runnable.
 

Neumi5694

Top Contributor
Das Ganze ist eh schon überkompliziert, da du nach jeder Zahl warten willst, bis die Auswertung beendet ist. Du brauchst überhaupt keinen Thread. Der ist nur sinnvoll, wenn du nicht wartest. Also nehm ich mal an, es geht dir darum, etwas über Threads zu lernen.

In meinen Vorschlägen wirst du selten ein System.out in einer Berechnung finden. Berechnung und Ausgabe gehören getrennt. Das Ergebnis der Berechnung soll im Normalfall weiterverwendbar sein. Deshalb die Consumer, was im jeweiligen Fall gemacht werden soll. Damit interessiert es die Berechnungsklasse nicht mehr, was der Caller mit dem Ergebnis macht.
Du wirst die Denkweise zu schätzen lernen, sobald du aufhörst, mit System.out zu arbeiten und stattdessen in Fenster oder 'echte' Logklassen logst.

Java stellt z.B. auch die SwingWorker Klasse zur Verfügung, die das Ganze standardisieren.

Dein erster Ansatz, wo's eine Thread-Klasse gibt, in die du eine Zahl zur Berechnung schickst, ist an sich auch ok, dann muss diese aber in einer Endlosschleife arbeiten und eine Queue abarbeiten. Vorteil: Nur ein Thread. Nachteil: Nur ein Thread, nur eine gleichzeitige Berechnung.

ps: Was ich hier nicht gemacht hab, ist bei Programmabbruch auf die Threads zu warten - das ist nur dann ein Thema, wenn man in der Schleife kein join() verwendet. Was sollte denn z.B. passieren, wenn die Schleife beendet wird und noch Berechnungen laufen?
Dazu müsste man alle Threads in einer Liste hinterlegen und nach der Schleife auf alle warten, für jeden Thread ein join aufrufen. Die Reihenfolge ist dabei nicht wichtig, der langsamste bestimmt das Tempo. Join wird also einfach auf alle Threads in der Liste angewendet.
Auch kann man zig Theads gleichzeitig starten, was auch nicht so schön ist, aber es ist halt nur ein Anschauungsbeispiel, wie man Berechnung im Hintergrund organisieren könnte.
 
Zuletzt bearbeitet:

Neumi5694

Top Contributor
Also bezogen auf meinen Code würde ich dann was verändern müssen, wenn es über Runnable laufen sollte?
ps: Nichts gegen das Runnable, das ist ok, nur eben kann das von sich aus kein Ergebnis liefern. Es kann irgendwo was reinschreiben, wenn es die Variable kennt, aber es ist halt nicht gekapselt. Verschiebst du es in eine andere Klasse, dann ist es unbrauchbar.
Falls die Aufgabe ist, zu ermitteln und als Ergebnis zu liefern, ob eine Zahl eine bestimmte Bedingung erfüllt, dann darf es dafür nicht an die Klasse gebunden sein, in der sich das Hauptprogramm befindet, diese Aufgabe muss es eigenständig lösen können, hat mit dem Rest ja nichts zu tun.
Selbst das direkte Ausgeben in die Kommandozeile funktioniert nur, weil System.out als Ziel bekannt ist. Pack das mal in eine UI ... Pech.
 

Wuast

Bekanntes Mitglied
Von mir gab es da für Dich nur eine etwas vereinfachte Lösung weil ich dachte, dass die ggf. für Dich einfacher zu verstehen ist.
Stimmt :D
Kann die anderen Dinge aber gut nachvollziehen. Immer wieder spannend so Tipps und Erklärungen aus der Praxis zu lesen.
Wenn Du warten willst, bis es fertig ist, dann nutz keinen Thread. Der Thread ist ja für die Nebenläufigkeit: Du willst im Hauptthread weiter Arbeiten (und hier konkret: weitere Eingaben abfragen). Das Verhalten, das Du hier verhindern willst, ist also doch explizit durch den Ansatz gefordert. Wenn Du das nicht willst, dann hast Du keinen Thread sondern einfach nur einen Aufruf isPrime(input) in einem if mit eine Ausgabe für beide Fälle. Da ist dann nirgends ein Thread oder Runnable.
Grundsätzlich ja. Aber es war ja auch nur eine Übungsaufgabe. Über Sinn und Unsinn der Aufgabenstellung mache ich mir da nur nachgelagert Gedanken. Ich muss einfach unterstellen, dass die Übungen ihren Zweck nicht verfehlen - ausgedacht hat sie sich ja jemand anderes.
Insofern stimmt das:
Also nehm ich mal an, es geht dir darum, etwas über Threads zu lernen.
Ging nur darum. Der Aufgabenschwerpunkt war ja auch ein anderer, als die Fragestellung im Thread hier (Forenthreads gibts ja auch noch :D )
In meinen Vorschlägen wirst du selten ein System.out in einer Berechnung finden. Berechnung und Ausgabe gehören getrennt. Das Ergebnis der Berechnung soll im Normalfall weiterverwendbar sein. Deshalb die Consumer, was im jeweiligen Fall gemacht werden soll. Damit interessiert es die Berechnungsklasse nicht mehr, was der Caller mit dem Ergebnis macht.
Du wirst die Denkweise zu schätzen lernen, sobald du aufhörst, mit System.out zu arbeiten und stattdessen in Fenster oder 'echte' Logklassen logst.
Werd ich mir hoffentlich merken!

Also nochmal herzlichen Dank an alle, hier ist für mich alles klar soweit. Meine nächste Frage wird bestimmt nicht allzu lange auf sich warten lassen ;)
 

Wuast

Bekanntes Mitglied
Okay, ich greife das nochmal kurz auf, um keinen neuen Thread zu machen. Ich hoffe, hier schaut noch jemand rein.
Bin ich denn vollkommen besche***t? :D Kann mir jemand nochmal einen Tipp geben zu folgendem?

Ich habe eine Schleife, über die int-Eingaben empfangen werden. Die sollen in eine ArrayList gespeichert werden, über die dann mittels Iteration drübergerutscht werden und deren Indezes dann zusammengerechnet werden sollen.
Abbruchbedingung ist die Konsoleneingabe -1. Habe es auch über die final quitNumber probiert, aber auf der Suche nach dem Fehler testweise durch den boolean ersetzt. (Nur als Hinweis, dass ich DAS nicht schon wieder vergessen habe).
Gebe ich als erstes die -1 in die Konsole ein, spuckt diese 0 raus. Klar, die List hat ja auch noch nichts bekommen.
Aber wenn ich eine Zahl eintippe, z.B. die 1, kann ich weitermachen und es passiert nichts mehr. Auch auf die -1 reagiert der Code dann nicht mehr. Aber warum? Was muss ich tun, damit a) die Eingabewerte in die Liste eingetragen werden und b) die Schleife bei -1 beendet wird?

(Die Kommentare sind Punkte, die ich bei der Fehlersuche noch mal ausprobiert habe)

Java:
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Scanner;

public class DieArrayList {

    public ArrayList <Integer> arList = new <Integer> ArrayList();
    ListIterator <Integer> arListIterator = arList.listIterator();
    
    private int zaehler = 0;    //s. Methode arListWerteZusammenrechnen
    
    
    public void arListFuellen() {    //ArrayList<Integer> arList überladen?!
        
        //this.arList = arList;    unnötig, da die arList überladen wird
        
        System.out.println("Zahlen eingeben. Zum Beenden der Eingabe '-1' eintippen.");
        
        boolean schleifeLaeuft = true;   
        
        do {
            int konsolenEingabe = new Scanner(System.in).nextInt();
            
            if (konsolenEingabe != -1) {
            arList.add(konsolenEingabe);
            }
            if (konsolenEingabe == -1) {
                schleifeLaeuft = false; 
            }
        }
        while (schleifeLaeuft);    //Abbruchbedingung wenn false -> -1
    
    //this.arList = arList;   
        
    //return this.arList;
    
    
    }
    
    
    
    
    public void arListWerteZusammenrechnen() {
    
        while (arListIterator.hasNext()) {
            //zaehler += arListIterator.next();

            for (int i = 0; i < arList.size(); i++) {
                    zaehler += arList.get(i);
            }       
                
        }
    }
    
    
    public int getZaehler() {
        return zaehler;
    }
    
}



public class Main {

    public static void main(String[] args) {
        
        DieArrayList arrayList = new DieArrayList();
        
        arrayList.arListFuellen();
        arrayList.arListWerteZusammenrechnen();
        System.out.println(arrayList.getZaehler());
        
    }

}
 

KonradN

Super-Moderator
Mitarbeiter
Dein Problem ist der Iterator. Bei einem Iterator iterierst Du ja durch alle Elemente. hasNext prüft nur: Gibt es ein nächstes Element. Dieses könnte man dann mit next() bekommen.

Das ist also ähnlich wie: Wenn Da ein Papier auf den Tisch liegt, dann machst Du etwas (aber nicht das Papier vom Tisch nehmen, also z.B. einmal Klatschen). Nach dem Klatschen schaust Du erneut auf den Tisch: Das Papier ist noch da. Also klatscht Du wieder :)

Generell ist es so, dass Du einen Iterator erst erzeugen solltest, wenn Du diesen auch nutzt. Das könnte also etwas sein wie:

Das wäre dann also tatsächlich einfach ein:
Java:
    public void arListWerteZusammenrechnen() {
        ListIterator <Integer> arListIterator = arList.listIterator();

        while (arListIterator.hasNext()) {
            zaehler += arListIterator.next();
        }
    }

Etwas in der Art hattest Du wohl auch schon - aber da hast Du eine Exception bekommen:
Wenn Du über eine Liste iterierst, dann darfst Du diese von außen nicht verändern. Auch das kannst Du Dir gut bildlich vorstellen:
Stell Dir vor, Du sollst irgendwas durchgehen und ständig nehmen Andere etwas weg oder fügen etwas hinzu. Würdest Du auch nicht mögen. :)
 

Wuast

Bekanntes Mitglied
AHHHHH okay, das macht Sinn. Und dann klappt es auch so wie es soll.

Und ich habe wieder etwas gelernt. Ich dachte schon, ich raff echt gar nichts mehr, aber dass der Iterator nicht erstmal erzeugt werden kann wie jedes andere Objekt auch und woraufhin dann der jeweilige Methodenaufruf folgt, ist natürlich gut zu wissen.
Stell Dir vor, Du sollst irgendwas durchgehen und ständig nehmen Andere etwas weg oder fügen etwas hinzu. Würdest Du auch nicht mögen. :)
Da kannst du einen drauf lassen :D
Es gibt Fehler, die macht man hoffentlich nur einmal...

Ich danke dir!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Anfänger2011 Wiederkehrende Klassen in Projekten Java Basics - Anfänger-Themen 5
-horn- Wie "Module" für wiederkehrende Aufgaben machen? Java Basics - Anfänger-Themen 7
W Streams in Java und was bedeutet meine Konsolen-Ausgabe? Java Basics - Anfänger-Themen 4
K Leerzeile in Konsolen-Ausgabe Java Basics - Anfänger-Themen 4
celta_vigo Konsolen-Fenster ist weg Java Basics - Anfänger-Themen 5
S Konsolen eingabe Java Basics - Anfänger-Themen 17
F Konsolen Befehl ausführen und Rückgabe auswerten Java Basics - Anfänger-Themen 3
H Frage zur Konsolen-Ausgabe Java Basics - Anfänger-Themen 1
J Möchte gern den Konsolen Output auf JTextPane umleiten Java Basics - Anfänger-Themen 4
I Externes konsolen Anwendung (.exe) starten Java Basics - Anfänger-Themen 2
E Jar Fehler = Konsolen Fehler Java Basics - Anfänger-Themen 4
P seltsamer konsolen aufruf Java Basics - Anfänger-Themen 8
W Konsolen-Ausgabe formatieren Java Basics - Anfänger-Themen 10
P konsolen ausgabe bei servlet Java Basics - Anfänger-Themen 2
D Konsolen aufruf geht nich Java Basics - Anfänger-Themen 2
A Java-Konsolen Menü Java Basics - Anfänger-Themen 6
E Java Programm zur anzeige, ob Winter- oder Sommerzeit herrscht Java Basics - Anfänger-Themen 62
Z Fehler Zeiterfassungsprogramm Anzeige Java Basics - Anfänger-Themen 3
Elyt Würfel mit bildlicher Anzeige Java Basics - Anfänger-Themen 2
S JavaFX-Arduino Kommunikation mit LCD-Anzeige Java Basics - Anfänger-Themen 0
A Anzeige Fehler auf anderem Gerät Java Basics - Anfänger-Themen 1
T Anzeige, wie lange es noch dauert bis ein File gesendet ist. Java Basics - Anfänger-Themen 2
Hijo2006 Anzeige eines Bildes in JAR Java Basics - Anfänger-Themen 12
B Erste Schritte Anzeige von Graphics Objekten einzeln aktualisieren Java Basics - Anfänger-Themen 1
TheSorm Anzeige fehler eines Buttons Java Basics - Anfänger-Themen 3
C Erste Schritte Berechnen einer Form mit Live anzeige.... Java Basics - Anfänger-Themen 4
H pdf-Anzeige Java Basics - Anfänger-Themen 11
J Anzeige erneuern, wie geht das? Java Basics - Anfänger-Themen 6
S ListModel - Anzeige im JList Java Basics - Anfänger-Themen 4
FetterOtter JTable: ToolTipText-Anzeige abhängig von Zellengröße und Textlänge Java Basics - Anfänger-Themen 2
S Probleme bei der Gui Anzeige Java Basics - Anfänger-Themen 11
S JPanel anzeige Java Basics - Anfänger-Themen 2
K Erste Schritte prob anzeige Java Basics - Anfänger-Themen 4
P Labyrinth, Backtracking, verzögerte Anzeige Java Basics - Anfänger-Themen 15
G JTextField() Anzeige - if-Anweisungen Java Basics - Anfänger-Themen 2
1 Combobox anzeige Java Basics - Anfänger-Themen 7
F grafische Anzeige von Werten Java Basics - Anfänger-Themen 2
D DB Anzeige der Treffer Java Basics - Anfänger-Themen 12
Weiti Anzeige von komponenten erst bei Mouse-Over Java Basics - Anfänger-Themen 3
S Zeitpunkt für die Anzeige von setBackground Java Basics - Anfänger-Themen 2
H Klassen zur Anzeige ines Bildes und zum Zeichnen innerhalb diese Bildes Java Basics - Anfänger-Themen 2
B double Rundungsfehler od. Anzeige-Fehler? Java Basics - Anfänger-Themen 4
D GUI Anzeige fehlt Java Basics - Anfänger-Themen 4
C Probleme mit Exportieren einer jar-datei /keine Anzeige mehr Java Basics - Anfänger-Themen 5
hdi Konsole basteln -> wie die Anzeige des Inhalts realiseren Java Basics - Anfänger-Themen 3
B Arbeitsspeicher-Verbrauch bei Anzeige eines 10MP-Bildes Java Basics - Anfänger-Themen 11
G Problem mit Anzeige der Tabelle Java Basics - Anfänger-Themen 3
G Ebenen Verwaltung und Anzeige Problem Java Basics - Anfänger-Themen 6
G JFileChooser - Anzeige beschleunigen Java Basics - Anfänger-Themen 2
O Anzeige von Zeichen in einer JList Java Basics - Anfänger-Themen 5
G 9-Segment-Anzeige Java Basics - Anfänger-Themen 7
B Java - Anzeige beim Refresh weiss Java Basics - Anfänger-Themen 11
T Keine Anzeige in JList Java Basics - Anfänger-Themen 18
B unvollständige Anzeige von JComboBox Werten Java Basics - Anfänger-Themen 5
C Taschenrechner -> Anzeige/Variablen Problem Java Basics - Anfänger-Themen 9
S JTextArea Problem mit Anzeige Java Basics - Anfänger-Themen 2
A Datei einlesen und Inhalt in verschidenen JList anzeige? Java Basics - Anfänger-Themen 3
G Array anzeige nur letzter wert Java Basics - Anfänger-Themen 2
M Keine Anzeige, wenn ich die Classe umbenenne Java Basics - Anfänger-Themen 13
V Problem mit der Anzeige einer paint-Methode in einem Panel Java Basics - Anfänger-Themen 2
G Problem mit JPanel, bekomme keine Anzeige! Java Basics - Anfänger-Themen 4
I Classpath Anzeige Java Basics - Anfänger-Themen 4

Ähnliche Java Themen

Neue Themen


Oben