# Befehl zum Verlassen einer Schleife



## chaostheory (5. Sep 2011)

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


----------



## Noctarius (5. Sep 2011)

[c]break;[/c] <- Schleifen
[c]return ...;[/c] <- komplette Methode


----------



## Ark (6. Sep 2011)

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:

```
meinLabel:
for(...){
    for(...){
        ...
        break meinLabel;
        ...
    }
}
// Hier geht's dann weiter
```
Ark


----------



## chaostheory (6. Sep 2011)

Hey, ich dachte break würde direkt die komplette Methode beenden, damit funktioniert es jetzt. Danke.


----------



## Noctarius (6. Sep 2011)

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 


```
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;
}
```


----------



## Tomate_Salat (6. Sep 2011)

Ark hat gesagt.:


> 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:
> 
> ```
> meinLabel:
> ...



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

Mach dann lieber soetwas (oder Noctarius' Lösungsvorschlag):

```
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;
			}
		}
	}
}
```


----------



## Ark (6. Sep 2011)

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


----------



## Noctarius (6. Sep 2011)

Dann macht man eben ValueObjects genau wie du meinst, neue Klassen.
Zur Not macht man ein paar Tuple Klassen.


----------



## Gast2 (6. Sep 2011)

Mich schockiert gerade, dass es sowas wie labels gibt :autsch:


----------



## Noctarius (6. Sep 2011)

kappesf hat gesagt.:


> Mich schockiert gerade, dass es sowas wie labels gibt :autsch:



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


----------



## Tomate_Salat (6. Sep 2011)

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:


```
....
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.


----------



## Noctarius (6. Sep 2011)

Also ich sehe das ähnlich. Selten kommt man in die Verlegenheit mehrere Schleifen zu schachteln. Das kann passieren wenn ich z.B.:

```
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.


----------



## Ark (6. Sep 2011)

kappesf hat gesagt.:


> Mich schockiert gerade, dass es sowas wie labels gibt :autsch:


Zähl doch mal hier die Anzahl der Labels:

```
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);
    }
}
```



Noctarius hat gesagt.:


> 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.



Tomate_Salat hat gesagt.:


> 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).



Tomate_Salat hat 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:



Tomate_Salat hat gesagt.:


> 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


----------



## Noctarius (6. Sep 2011)

Ark hat gesagt.:


> Zähl doch mal hier die Anzahl der Labels:
> 
> ```
> public void foo(char c){
> ...



Lass mich kurz *ääääähhhhhhhhhhm*
0


----------



## Gast2 (6. Sep 2011)

ich nutze lieber ein folgendes Konstrukt: 


```
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.


----------



## Tomate_Salat (6. Sep 2011)

Ark hat gesagt.:


> 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.


----------



## faetzminator (6. Sep 2011)

Noctarius hat gesagt.:


> Lass mich kurz *ääääähhhhhhhhhhm*
> 0



Ist [c]default[/c] kein Label?


----------



## Noctarius (6. Sep 2011)

Ich habe Eclipse so eingestellt, dass er bei einem Save automatisch final einsetzt, überall (außer an Typen - also Klassen, Enums, Interfaces).

Ich finde die Regel für überall final gut, das zeigt beim Lesen schon "ich will nicht, dass dieser Wert verändert wird".




faetzminator hat gesagt.:


> Ist [c]default[/c] kein Label?


Nein default ist in Switch-Statements ein Keyword.
List of Java keywords - Wikipedia, the free encyclopedia


----------



## Gast2 (6. Sep 2011)

Noctarius hat gesagt.:


> 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!


----------



## Tomate_Salat (6. Sep 2011)

Noctarius hat gesagt.:


> 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:


----------



## Noctarius (6. Sep 2011)

kappesf hat gesagt.:


> 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!



Window -> Preferences -> Java -> Editor -> Save Actions


----------



## Ark (6. Sep 2011)

Tomate_Salat hat gesagt.:


> 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. 



Tomate_Salat hat gesagt.:


> 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.



Noctarius hat gesagt.:


> faetzminator hat gesagt.:
> 
> 
> > Ist [c]default[/c] kein Label?
> ...


Alle cases und defaults sind Labels: 14.11 The switch Statement

Ark


----------



## Spacerat (6. Sep 2011)

Ark hat gesagt.:


> Alle cases und defaults sind Labels


So steht's zwar da, hast aber falsch verstanden. Versuch mal so einen *case*-label mit *break* oder *continue* anzuspringen


----------



## Fu3L (6. Sep 2011)

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?


----------



## Tomate_Salat (6. Sep 2011)

Ark hat gesagt.:


> (gibt es eigentlich veränderbare Konstanten? )


Jein. Wenn du das als konstante ansiehst:

```
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.


----------



## Noctarius (6. Sep 2011)

Ark hat gesagt.:


> Alle cases und defaults sind Labels: 14.11 The switch Statement



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.


----------



## Ark (6. Sep 2011)

Spacerat hat gesagt.:


> 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.



Noctarius hat gesagt.:


> 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.



Tomate_Salat hat gesagt.:


> 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


----------



## Spacerat (6. Sep 2011)

@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.


----------

