![]() |
|
|
Eine genauere Betrachtung der Schleife zeigt die unterschiedlichen Segmente:
Betrachten wir das Beispiel, so ist die Auswertungsreihenfolge folgender Art:
SchleifenzählerWird die for-Schleife zum Durchlaufen einer Variablen genutzt, so heißt der Schleifenzähler entweder Zählvariable oder Laufvariable.
Wichtig ist die Initialisierung und die korrekte Abfrage am Ende. Schnell läuft die Schleife einmal zu oft durch und führt so zu falschen Ergebnissen. Die Fehler bei der Abfrage werden auch »off-by-one error« genannt, wenn zum Beispiel statt <= der Operator < steht. Dann nämlich läuft die Schleife nur bis 9. Ein anderer Name für den Schleifenfehler heißt »fencepost error«. Es geht um die Frage, wie viele Pfähle nötig sind, um 100 m einzuzäumen, sodass alle Pfähle einen Abstand von 10 m haben: 9, 10, 11? Wann for und wann while?Da sich die while- und for-Schleife sehr ähnlich sind, besteht die berechtigte Frage, wann die eine und wann die andere zu nutzen ist. Leider verführt die kompakte for-Schleife sehr schnell zu einer Überladung. Manche Programmierer packen gerne alles in den Schleifenkopf hinein, und der Rumpf besteht nur aus einer leeren Anweisung. Dies ist ein schlechter Stil und muss vermieden werden. for-Schleifen sollten immer dann benutzt werden, wenn eine Variable um eine konstante Größe erhöht wird. Tritt in der Schleife keine Schleifenvariable auf, die inkrementiert oder dekrementiert wird, sollte eine while-Schleife genutzt werden. Eine do/while-Schleife sollte dann ihren Einsatz finden, wenn die Abbruchbedingung erst am Ende eines Schleifendurchlaufs ausgewertet werden kann. Auch sollte die for-Schleife dort eingesetzt werden, wo sich alle drei Ausdrücke im Schleifenkopf auf dieselbe Variable beziehen. Vermieden werden sollten unzusammenhängende Ausdrücke im Schleifenkopf. Der Zugriff auf die Schleifenvariable im Rumpf ist eine schlechte Idee, wenn sie auch gleichzeitig im Kopf modifiziert wird – das ist schwer zu durchschauen. Wie Bereichsangaben schreiben?Für Bereichsangaben der Form a >= 23 && a <= 42 ist es empfehlenswert, den unteren Wert mit in den Vergleich einzubeziehen, den Wert für die obere Grenze jedoch nicht (inklusive untere Grenzen und exklusive obere Grenzen). Für unser Beispiel, in dem a im Intervall bleiben soll, ist Folgendes besser: a >= 23 && a < 43. Die Begründung dafür ist einleuchtend:
Die Vorschläge können für normale Schleifen mit Vergleichen übernommen werden. So ist eine Schleife mit zehn Durchgängen besser in der Form for ( i = 0; i < 10; i++ ) formuliert als in der semantisch äquivalenten Form for ( i = 0; i <= 9; i++ ) Eine Endlosschleife mit forDa alle drei Ausdrücke im Kopf der Schleife optional sind, können sie weggelassen werden, und es ergibt sich eine Endlosschleife. Diese Schreibweise ist somit semantisch äquivalent mit while(true): for ( ; ; ) ; Die trennenden Semikolons dürfen nicht verschwinden. Falls demnach keine Schleifenbedingung angegeben ist, ist der Ausdruck immer wahr. Es folgt keine Initialisierung und keine Auswertung des Fortschaltausdrucks. Geschachtelte SchleifenSchleifen, und das gilt insbesondere für for-Schleifen, können geschachtelt werden. Syntaktisch ist das auch logisch, da sich innerhalb des Schleifenrumpfs beliebige Anweisungen aufhalten dürfen.
Die übergeordnete Schleife nennt sich äußere Schleife, die untergeordnete innere Schleife. In unserem Beispiel wird die äußere Schleife die Zeilen zählen und die innere die Sternchen in eine Zeile ausgeben, also für die Spalte verantwortlich sein. Da Schleifen beliebig tief geschachtelt werden können, muss besonders ein Auge auf die Laufzeit geworfen werden. Die inneren Schleifen werden immer so oft ausgeführt, wie die äußere Schleife durchlaufen wird. for-Schleifen und ihr Komma-OperatorIm ersten und letzen Teil einer for-Schleife lässt sich ein Komma einsetzen. Damit lassen sich entweder mehrere Variablen gleichen Typs deklarieren – wie wir es schon kennen – oder mehrere Ausdrücke nebeneinander schreiben.4
Ein weiteres Beispiel mit komplexerer Bedingung.
Wird das Komma für die Deklaration mehrerer Variablen verwendet, so kann dahinter kein Ausdruck mit Komma abgetrennt werden. Wenn der Compiler mit einer Deklaration beginnt, könnte er gar nicht zwischen einer zweiten Deklaration für eine Variable und dem folgenden Ausdruck unterscheiden, da das Komma die Variablennamen abtrennt.
Der erste Teil leitet eine Anweisung ein. Nach dem Komma folgt für den Compiler aber die Deklaration einer zweiten Variablen. Da sie jedoch schon eine Zeile vorher definiert wurde, meldet der Compiler einen Fehler. Auch umgekehrt funktioniert das nicht, denn eine Variablendeklaration ist kein Ausdruck, sie ist formal betrachtet eine Anweisung.
Im letzten Teil von for, dem Fortschaltausdruck, darf keine Variablendeklaration stehen. Wozu sollte das auch gut sein? Zu den weiteren Einschränkungen gehört, dass es nicht möglich ist, Variablen unterschiedlicher Typen zu deklarieren, wie es etwa for (int i = 0, double d = 0.0;;) zeigt. Hier muss eine Variable außerhalb der for-Schleife definiert werden. Das Deklarieren einer äußeren Variable bringt vielleicht aber auch den unerwünschten Effekt mit sich, dass eine Variable, die eigentlich nur in der Schleife gültig sein soll, eine zu große Sichtbarkeit bekommt. Dann lässt sich ein Block aufspannen, in dem dann nur eine Variable gültig ist.
2.6.5 Ausbruch planen mit break und Wiedereinstieg mit continue
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Beispiel Führe die Schleife so lange durch, bis i den Wert 0 hat.
int i = 10; while ( true ) if ( i-- == 0 ) break; |
Die Anweisung ist nützlich, um im Programmblock festzustellen, ob die Schleife noch einmal durchlaufen werden soll. Sie entlastet den Schleifenkopf, der sonst die Bedingung testen würde. Da ein kleines break jedoch im Programmtext verschwinden könnte, die Bedeutung aber groß ist, sollte ein kleiner Hinweis auf diese Anweisung gesetzt werden.
break lässt sich gut benutzen, anstatt mit Flags aus einer Schleife vorzeitig auszubrechen. Dazu ein Beispiel, was vermieden werden sollte:
boolean endFlag = false; do { if ( Bedingung ) { // Code ohne Ende endFlag = true; } } while ( weitereBedingung && !endFlag );
Stattdessen schreiben wir:
do { if ( Bedingung ) { // Code wieder ohne Ende break; } } while ( weitereBedingung );
Die alternative Lösung stellt natürlich einen Unterschied dar, wenn nach dem if noch Anweisungen in der Schleife stehen.
Innerhalb einer for-, while- oder do/while-Schleife lässt sich eine continue-Anweisung einsetzen, die nicht wie break die Schleife beendet, sondern zum Schleifenkopf zurückgeht, sodass dort eine neue Prüfung durchgeführt werden kann, ob die Schleife weiter durchlaufen werden soll. Ein häufiges Einsatzfeld sind Schleifen, die im Rumpf immer wieder Werte so lange holen und testen, bis sie passend zur Weiterverarbeitung sind.
Beispiel Gib die geraden Zahlen von 0 bis 10 aus.
for ( int i = 0; i <= 10; i++ ) { if ( i % 2 == 1 ) continue; <span class="listing">System.out.println( i + " ist eine gerade Zahl" ); }</span> |

Hier klicken, um das Bild zu Vergrößern
Manche Programmstücke sind aber ohne continue lesbarer. Ein continue am Ende einer if-Abfrage kann durch einen else-Teil bedeutend klarer gefasst werden. Zunächst das schlechte Beispiel:
while ( Bedingung ) // Durch continue verzuckert { if ( NochNeBedingung ) { // Code,Code, code continue; } // Weiterer schöner Code }
Viel deutlicher ist:
while ( Bedingung ) { if ( NochNeBedingung ) { // Code, Code, Code } else { // Weiterer schöner Code } }
Obwohl das Schlüsselwort goto in der Liste der reservierten Wörter auftaucht, ist diese Operation nicht erlaubt. Programmieren mit goto sollte vermieden werden. Mit dem Konzept von break lässt sich gut leben, und es kann auch noch ruhigen Gewissens eingesetzt werden. Doch zum Schrecken vieler kann break noch schmutziger eingesetzt werden, nämlich mit einer Sprungmarke. Das bringt Java verdächtig nahe in die goto-Welt der unstrukturierten Programmiersprachen, was die Entwickler eigentlich vermeiden wollten. Da jedoch Abbruchbedingungen – der häufigste Einsatzort eines goto – vereinzelt auftreten, wurden in Java break und continue mit Sprungmarken eingeführt.
Beispiel Der Einsatz von break oder continue:
one: while ( condition ) { ... two: while ( condition ) { ... |
// break oder continue
}
// nach two
}
// nach one
|
Wird innerhalb der zweiten while-Schleife ein break platziert, dann würde es beim Aufruf die while-Schleife beenden. Das continue würde zur Fortführung der while-Schleife führen. Dieses Verhalten entspräche C, aber in Java ist es erlaubt, hinter den Schlüsselworten break und continue Sprungmarken zu setzen. Das C-Verhalten kann in Java mit break two oder continue two beschrieben werden. Dass aber auch beispielsweise break one möglich ist, zeigt die Mächtigkeit dieses Befehls. Durch break und continue mit Marken ist daher ein goto nahezu überflüssig.
Rätsel Warum übersetzt der Compiler Folgendes ohne Murren?
class OhneMurren { static void main( String[] args ) { http://java-tutor.com/ System.out.print( "Das gibt's Java Tipps und Tricks." ); } } |
1 Integer.MAX_VALUE + Integer.MAX_VALUE + 2 ist wieder gleich 0. Die Schleife muss also »nur« 4.294.967.296 Mal durchlaufen werden.
2 Das ist in Pascal anders! Hier läuft die Schleife so lange, bis die Bedingung erfüllt ist und bricht dann ab.
3 Im Gegensatz zu C++ ist das Verhalten klar definiert, und es gibt kein hin und her. In C++ implementierten Compilerbauer die Variante einmal so, dass die Variable nur im Block gilt, andere interpretierten die Sprachspezifikation so, dass diese auch außerhalb gültig blieb. Die aktuelle C++-Definition schreibt nun vor, dass die Variable außerhalb des Blocks nicht mehr gültig ist. Da es jedoch noch alten Programmcode gibt, haben viele Compilerbauer eine Option eingebaut, mit der das Verhalten der lokalen Variablen bestimmt werden kann.
4 Wenn Java eine ausdrucksorientierte Sprache wäre, dann könnten wir hier beliebige Programme hineinlegen.
| << zurück |
Copyright © Galileo Press GmbH 2005
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.