Befehl zum Verlassen einer Schleife

chaostheory

Bekanntes Mitglied
Hallo,
ich habe in einer Methode eine while-Schleife, in der wiederum mehrere einzelne while-Schleifen sind. Ich suche nun einen Befehl, der eine Schleife verlässt. Ich kenne nur break, das meines Wissens nach aber die komplette Methode beendet!? Gibt es einen Befehl, der nur die eine Schleife verlässt?

Grüße
 
Wenn du mehrere geschachtelte Schleifen hast, verlässt [c]break[/c] nur die nächste umgebende ("aktuelle"). Solltest du stattdessen aus mehreren Schleifen gleichzeitig ausbrechen wollen, musst du mit Labels arbeiten:
Java:
meinLabel:
for(...){
    for(...){
        ...
        break meinLabel;
        ...
    }
}
// Hier geht's dann weiter
Ark
 
Nein man sollte nicht mit Labels arbeiten! Pfui bäh!

Dann sollte man die zweite Schleife in eine eigene Methode auslagern um Verschachtelung und solche hässlichen Konstrukte wie Label-Breaks (früher nannte man so einen Schmarn Goto) zu unterbinden.

Das Java allein solche eine Möglichkeit bietet gehört verboten 🙂

Java:
public boolean found(Matrix matrix) {
  for (MatrixRow row : matrix.getRows()) {
    if (found(row)) {
      return true;
    }
  }
  return false;
}

private boolean found(MatrixRow row) {
  for (MatrixColumn column : row.getColumns()) {
    if (isSolution(column)) {
      return true;
    }
  }
  return false;
}
 
Zuletzt bearbeitet:
Wenn du mehrere geschachtelte Schleifen hast, verlässt [c]break[/c] nur die nächste umgebende ("aktuelle"). Solltest du stattdessen aus mehreren Schleifen gleichzeitig ausbrechen wollen, musst du mit Labels arbeiten:
Java:
meinLabel:
for(...){
    for(...){
        ...
        break meinLabel;
        ...
    }
}
// Hier geht's dann weiter
Ark

Nein, aus, böse! Hörst du auf Gotos zu empfehlen 😀.

Mach dann lieber soetwas (oder Noctarius' Lösungsvorschlag):
Java:
public static void main(String[] args) 
{
	boolean outer=true;
	
	for(int i=0;i<100 && outer;i++) {
		for(int j=0;j<100;j++) {
			System.out.println(i + " " + j);
			if(j==10) {
				outer=false;
				break;
			}
		}
	}
}
 
Für euch sind es gotos, für mich ist es ein "ich hätte ja am liebsten return gesagt, aber leider geht es in der Methode noch weiter". 😉

@Noctarius: Was machst du denn, wenn du in solchen geschachtelten Schleifen verschiedene lokale Variablen aktualisieren musst (z.B. Maxima und Summen ermitteln), weil du diese Werte später (z.B. hinter der inneren Schleife, aber noch in der äußeren Schleife und auch nach den Schleifen) benötigst? In Java "mal eben" mehrere Werte zurückgeben? Geht so direkt nicht. Eigene Klasse anlegen? Macht die Sache komplexer und komplizierter, als sie ist. Objektvariablen verwenden? Hat was von Missbrauch.

Da gefällt mir der Vorschlag von Tomate_Salat schon besser. Allerdings hat er (der Vorschlag, nicht der Salat 😀) auch ein paar Schönheitsfehler: Wenn mehrere solcher Schleifen aufeinanderfolgen, müsste man [c]outer[/c] entweder nach der Schleife wieder zurücksetzen (potentielle Fehlerquelle!), oder noch mehr Namen für solche Flags verbrauchen. Außerdem können diese Flags nicht final sein, was zumindest mich wesentlich mehr stört als ein paar Labels.

Ark
 
wieso willst du diese variablen final machen?
Wieviele schleifen willst du den verschachteln? Bei mir ist das eher die Seltenheit, dass ich mehrere Schleifen ineinander habe.
Labels sind imho nicht schöner, als 2 weitere Variablen (im Notfall könntest du auch z.B. [c]i[/c] hochsetzen was ich aber unschön fände).
Wenn es einer Berechnung dient, und du dann aus 2 Schleifen ausbrechen musst, kannst du diese auch in eine Methode stecken:

Java:
....
int ergebnis=calc(100,102982);

public int calc(int a, int b) {
   for(int i=0;i<a;i++) {
        for(int j=0;j<b;j++) {
              if(j==42) return b*a;
        }
   }
}

imho brauchst du Labels nicht. Es gibt immer eine "schönere" Alternative zu Spagethicode.
 
Also ich sehe das ähnlich. Selten kommt man in die Verlegenheit mehrere Schleifen zu schachteln. Das kann passieren wenn ich z.B.:
Java:
for (Channel channel : channelManager.getChannels()) {
  for (User user : channel.getUsers()) {
    // ...
  }
}

Wenn ich dann aber unsaubere Abbruchbedingungen habe, dann muss ich die Schleifen halt auf Methoden aufteilen.
 
Mich schockiert gerade, dass es sowas wie labels gibt :autsch:
Zähl doch mal hier die Anzahl der Labels:
Java:
public void foo(char c){
    switch(c){
        case '0':
        case '1':
        case '2':
        case '3':
            a += c - '0';
            break;
        case '+':
        case '-':
            b.append(c);
            break;
        default:
            throw new IllegalArgumenException("illegal character: " + c);
    }
}

Leider ist ja auch goto ein reserved keyword und ich hoffe, dass niemals nie nicht... Ihr wisst schon 🙂

Ich hätte wohl auch ein Problem mit goto. 😉 In Java können Labels aber nicht einfach irgendwo hingesetzt werden, und goto gibt es ja auch nicht. Insofern bin ich der Meinung, dass dies mit Java schon ein guter Mittelweg ist.

wieso willst du diese variablen final machen?
Je mehr final ist, desto besser (im Allgemeinen, gilt übrigens auch für Klassen). Oder treffender gesagt: Je mehr nicht-final, desto schlimmer. So ist zumindest meine Erfahrung. Je weniger man ändern kann, desto weniger kann man kaputt machen (mal ganz einfach gesagt).

Wieviele schleifen willst du den verschachteln? Bei mir ist das eher die Seltenheit, dass ich mehrere Schleifen ineinander habe.
Bei mir ist es auch eher eine Seltenheit. Und noch viel seltener brauche ich dabei Labels. Deshalb verstehe ich auch nicht so ganz, was an Schleifenlabels so verwerflich sein soll. Unstrukturiert programmieren kann man auch ohne Labels. Und nur wegen solcher seltenen Fälle eigene Klassen anlegen zu wollen/müssen, hat was von "mit Kanonen auf Spatzen schießen" oder "für jede Kleinigkeit ein Framework entwickeln". Deswegen ist das einfach nicht mein Weg. :bahnhof:

Wenn es einer Berechnung dient, und du dann aus 2 Schleifen ausbrechen musst, kannst du diese auch in eine Methode stecken […]
Siehe oben: das funktioniert nur elegant, solange du dafür kein eigenes Objekt brauchst, weil du mehr als einen Wert zurückgeben musst.

Ark
 
Zuletzt bearbeitet:
Zähl doch mal hier die Anzahl der Labels:
Java:
public void foo(char c){
    switch(c){
        case '0':
        case '1':
        case '2':
        case '3':
            a += c - '0';
            break;
        case '+':
        case '-':
            b.append(c);
            break;
        default:
            throw new IllegalArgumenException("illegal character: " + c);
    }
}

Lass mich kurz *ääääähhhhhhhhhhm*
0 😀
 
ich nutze lieber ein folgendes Konstrukt:

Java:
if("bedingung") {
} else if ("weitere bedingung") {
} else {
}

Ich find das Debugging von nem switch case Konstrukt manchmal extrem nervig, vor allem wenn mal wieder ein break vergessen wurde.

Das man Labels jedoch außerhalb von nem switch nutzen kann hat mich erschreckt.
 
Je mehr final ist, desto besser (im Allgemeinen, gilt übrigens auch für Klassen). Oder treffender gesagt: Je mehr nicht-final, desto schlimmer. So ist zumindest meine Erfahrung. Je weniger man ändern kann, desto weniger kann man kaputt machen (mal ganz einfach gesagt).
Man kanns übertreiben. Nicht alles muss final sein, du brauchst auch noch veränderbare Variablen! Klassen sollte man immer dann final machen, wenn man nicht will, dass von ihnen geerbt wird. Parameter sollte man imho immer final machen (vergesse ich gerne, deswegen habe ich mein Eclipse eingestellt, dass es als Error behandelt wird).
Sorry, aber imho kein Grund gegen diese flags.

Siehe oben: das funktioniert nur elegant, solange du dafür kein eigenes Objekt brauchst, weil du mehr als einen Wert zurückgeben musst.
Was ist den an Objekten nicht elegant oO. Meine Erinnerung kann falsch sein, aber gerade wenn ich solche verschachtelungen habe, habe ich afaik auch immer Objekte, an denen ich arbeite.
 
Ich habe Eclipse so eingestellt, dass er bei einem Save automatisch final einsetzt, überall (außer an Typen - also Klassen, Enums, Interfaces).

Sry für OT aber genau das Feature such ich schon ewig in den Einstellungen! Wo genau stellt man das ein. Will das schon seit Wochen machen seit ich auf Eclipse umgestiegen bin!
 
Ich habe Eclipse so eingestellt, dass er bei einem Save automatisch final einsetzt, überall (außer an Typen - also Klassen, Enums, Interfaces).
auch nett, muss ich mir mal ansehen.

Ich finde die Regel für überall final gut, das zeigt beim Lesen schon "ich will nicht, dass dieser Wert verändert wird".
wo es Sinn macht, ja, aber um etwas non-finales zu umgehen ein Goto-Konstrukt einsetzen. :noe:
 
Man kanns übertreiben. Nicht alles muss final sein, du brauchst auch noch veränderbare Variablen!
Man braucht keine veränderbaren Variablen, wenn man nur oft genug kopiert (siehe auch: Rekursion, funktionale Programmierung). Veränderbare Variablen (gibt es eigentlich veränderbare Konstanten? 😀) erscheinen schon nützlich und dürfen natürlich auch Verwendung finden. "Je mehr final, desto besser", widerspricht dem aber auch nicht wirklich. 😉

Was ist den an Objekten nicht elegant oO. Meine Erinnerung kann falsch sein, aber gerade wenn ich solche verschachtelungen habe, habe ich afaik auch immer Objekte, an denen ich arbeite.
In solchen Fällen hast du natürlich Glück gehabt. Ich habe auch nichts gegen Objekte an sich, sondern dagegen, dass Wegwerf-Klassen für Wegwerf-Objekte mit Wegwerf-Zuständen erzeugt werden, nur um scheinbare Unzulänglichkeiten einer Sprache zu begegnen.

Alle cases und defaults sind Labels: 14.11 The switch Statement

Ark
 
Sehe das ähnlich wie Ark. Was regt ihr euch über ein kleines continue outer; so auf?^^ 😉
Bevor ich alles in zig Objekte verkapsle, mach ich lieber mal ne etwas längere Schleife. Und bevor ich immer eine boolean-variable mit rumschleppe, setz ich lieber ein Label. Bei zu komplizierten Gebilden nutze ich auch solche Wrapper-Objekte, klar, aber nicht für jede Kleinigkeit.
Das ist wohl eher Geschmackssache und auch immer unterschiedlich was man programmiert. Performancekritische Anwendungen? Oder ne GUI-Büro-Anwendung wo man selbst mit Pech die CPU und das RAM nicht auslasten kann?
 
(gibt es eigentlich veränderbare Konstanten? 😀)
Jein. Wenn du das als konstante ansiehst:
Java:
final int SOME_VAR=42;

dann ja. Per reflection oder JNI kannst du diesen Wert ändern. Ich glaube, mit einem SecurityManager kann man ersteres unterbinden, aber JNI geht glaube ich immer.

In solchen Fällen hast du natürlich Glück gehabt. Ich habe auch nichts gegen Objekte an sich, sondern dagegen, dass Wegwerf-Klassen für Wegwerf-Objekte mit Wegwerf-Zuständen erzeugt werden, nur um scheinbare Unzulänglichkeiten einer Sprache zu begegnen.

Wie gesagt, dann löst man das notfalls über diese Flags. Du brauchst ja nicht unbedingt einmal flags, du kannst auch Methoden nehmen, in denen du noch Prüfungen durchführen kannst.
 
So steht's zwar da, hast aber falsch verstanden. Versuch mal so einen case-label mit break oder continue anzuspringen 😉
Ein Label ist, einfach gesagt, ein Hinweis im Quelltext, damit du Anweisungen wie [c]break[/c], [c]switch[/c] oder [c]continue[/c] mitteilen kannst, auf welche Stelle im Quelltext du dich jeweils beziehst, quasi "wo es weitergeht". Auch switch-Labels haben diesen Zweck: Sagen, wo es weitergeht. Deswegen erscheint es auch nicht unbedingt unnatürlich, dass switches mit fallthrough daherkommen. Du sagst mit switch-case eben nur: "Ab hier, bitte". Dass danach noch weitere Labels kommen, stört die JVM nicht, und sie hält sich auch nicht daran auf. Labels sind nur Markierungen, keine Anweisungen oder Ähnliches.

Da steht einfach nur als Begriff das Wort Label. Das hat aber Spec mäßig nichts mit dem Label als Ansprungspunkt gemeinsam, denn offiziell heißen diese Label [c]Foo:[/c] Break Targets.
Wie gerade beschrieben: Labels sind nur Markierungen. Wie sie tatsächlich verwendet werden oder wann sie in welcher Form erlaubt sind, steht auf einem völlig anderen Blatt.

Die JLS versteht unter "break target" die Anweisung, auf die sich ein [c]break[/c] bezieht: 14.15 The break Statement Im Falle einer ganz simplen for-Schleife mit [c]break[/c] (ohne Label!) ist das "break target" eben diese umgebende for-Schleife. Ein Label hilft nur, um klar zu machen, welche Anweisung gemeint ist, wenn man vom standardmäßigen "break target" abweichen und eben eine andere Anweisung als "break target" nutzen möchte.

Das, was du als "Break Target" anführst, ist einfach nur ein Label: 14.7 Labeled Statements In diesem Abschnitt der JLS steht auch nichts von "break target"; diese Vokabel taucht nur im Abschnitt über [c]break[/c] auf.

Wie gesagt, dann löst man das notfalls über diese Flags. Du brauchst ja nicht unbedingt einmal flags, du kannst auch Methoden nehmen, in denen du noch Prüfungen durchführen kannst.
Im Gegensatz zu Flags ist der Verwendungszweck von Labels klar. Der ist sogar so klar, dass eine IDE wie Eclipse dich warnen kann, wenn du ein Label nicht benutzt. Bei einem Flag funktioniert unter anderem das nicht.

Ark
 
Zuletzt bearbeitet:
@Ark: ^^ ...aber dennoch sind die beiden Labelarten verschieden. Bei switch ergeben sie sich aus der Tatsache, dass jedes Programm auf Prozessorebene prozedural ausgeführt wird, was an einem in OOPs und ebenso in Java vorbei gehen sollte. break-Labels sind prozedurale Programmiertechnik und haben in OOPs nichts verloren und das gilt auch für Java.
 
Zuletzt bearbeitet von einem Moderator:

Zurück
Oben