Java Standard: Kontrollstrukturen

Aus Wikibooks


Verzweigung (if)[Bearbeiten]

Eine einfache Verzweigung wird durch das "if-then-else"-Konstrukt gelöst, wobei lediglich if und else in Java Schlüsselwörter sind.

if (<boolescher Ausdruck>) {
  // Anweisung(en) 1
} else {
  // Anweisung(en) 2
}

Eine if-Verzweigung führt stets die nachfolgende Anweisung aus, wenn der <boolesche Ausdruck> wahr ist. Sollen mehrere Anweisungen ausgeführt werden so sind diese in einen Block zusammenzufassen (mit Hilfe der geschweiften Klammern). Die else Bedingung ist optional - auch hier gilt dass mehrere Anweisungen in einen Block zusammenzufassen sind.

boolean beenden = false;
//[...]
if (beenden) 
  System.out.println ("Oh ich soll mich beenden");
  System.exit(0);

Das vorstehende Beispiel zeigt einen typischen Fehler in Zusammenhang mit dem if-Konstrukt. Der Befehl System.exit(0); wird immer ausgeführt, da kein Block gebildet wurde.

Es ist auch eine Frage des guten Programmierstils solche if-Abfragen immer in geschweifte Klammern zu fassen, dadurch lassen sich die einzelnen Ausdrücke besser dem jeweiligen if zuordnen.

boolean beenden = false;
//[...]
if (beenden) {
  System.out.println ("Oh ich soll mich beenden");
}
  System.exit(0);

Beim unteren Quelltext wird im Gegensatz zum oberen klar, das System.exit(0) immer ausgeführt wird, da es nicht in den Klammern steht.

Ternärer Operator (?:)[Bearbeiten]

Wenn nur zwischen zwei Ausgabewerten unterschieden werden soll, so gibt es für die If-Then-Else-Anweisung eine Kurzform; und zwar den "Ternary-Operator".

(<boolescher Ausdruck>) ? AusgabewertTrue : AusgabewertFalse;
Beispiel

Anstelle der Anweisung

 //[...]
 if (gender.equals("männlich")) {
    System.out.println ("Sehr geehrter Herr");
 } else {
    System.out.println ("Sehr geehrte Frau");
 }

kann man kürzer schreiben

 System.out.println( (gender.equals("männlich") ) ? "Sehr geehrter Herr" : "Sehr geehrte Frau");

oder vielleicht etwas eleganter

 System.out.println( "Sehr geehrte" +(gender.equals("männlich") ? "r Herr" : " Frau" ));

Mehrfachverzweigung (switch)[Bearbeiten]

Das if-Konstrukt führt in Zusammenhang mit mehreren Möglichkeiten meist zu einer unschönen Kaskadierung. Hier kann switch helfen. Um dieses einzusetzen müssen Sie einen Datentyp int abprüfen bzw. einen kleineren (also byte, short, char), da dieser durch die JVM automatisch gecastet wird.

 switch (myIntWert) {
 case 0 : 
     System.out.println ("Mein Wert ist 0.");
     break;
 
 case 1 : 
     System.out.println ("Mein Wert ist 1.");
 
 case 2 :
     System.out.println ("Mein Wert ist 1 oder 2.");
     break;
 
 default :
     System.out.println ("Ich habe einen anderen Wert.");
 }

Eine switch Anweisung wird stets mit dem Schlüsselwort case und meist mit default und break verwendet. Der Wert hinter dem case muss eine Konstante sein und dient dem Vergleich mit dem übergebenen Wert (hier myIntWert). Wenn diese gleich sind werden alle Anweisungen bis zum nächsten break oder dem Ende des Blocks ausgeführt. Wurden keine Übereinstimmung gefunden so werden die Anweisung nach default ausgeführt. Seit Java 7 ist es ebenfalls möglich, den Datentyp String in Switch-Anweisungen zu verwenden. Zuvor war es seit Java 5.0 lediglich möglich, anstelle von String den Datentyp enums zu benutzen.

For-Schleife[Bearbeiten]

Die for-Schleife oder Zählschleife zählt von einem vorgegebenen Startwert zu einem ebenfalls vorgegebenen Endwert und führt für jeden Schritt von Start- bis Endwert alle Anweisungen im Schleifenkörper aus. Es muss also zusätzlich festgelegt werden, in welchen Intervallen bzw. Schritten von Start bis Ende gezählt wird.

For-Schleifen bestehen aus folgenden Teilen bzw. Anweisungen und Bedingungen:

  • Schleifenkopf
    • Initialisierung der Zählervariable auf den Startwert
    • Startbedingung mit Limitierung auf den Endwert - muss immer einen boolschen Wert ergeben (true | false)
    • Anweisung zum Zählen
  • Schleifenkörper
    • Anweisungen, die pro Schleifendurchlauf ausgeführt werden sollen

Die Syntax[Bearbeiten]

Die grundlegende Syntax sieht folgendermaßen aus:

for(/*Initialisierung Zählervariable*/; /*Startbedingung*/; /*Zählen*/) {
	//...
	//Schleifenkörper mit Anweisungen
	//...
}

// Bsp.: for-Schleife, die von 0 bis 9 in 1er-Schritten
// durchlaufen wird
for(int i=0; i < 10; i++) {
	//...
	//Anweisungen;
	//...
}

In obigem Beispiel sieht man eine for-Schleife, die von 0 bis 9 zählt. Warum nur bis 9? Weil die Startbedingung i kleiner als 10 und nicht kleiner gleich 10 lautet.

  • Zunächst muss eine Zählervariable auf einen Startwert initialisiert werden int i=0. Wird diese Variable im Schleifenkopf deklariert, ist sie auch innerhalb ihres Namensraumes, also dem Schleifenkopf selbst sowie dem Schleifenkörper bekannt. Außerhalb der Schleife kann die Zählervariable folglich nicht angesprochen werden.
  • Dann wird die Startbedingung für die for-Schleife festgelegt: i < 10. Sie läuft also "solange i kleiner als 10 ist". Trifft diese Bedingung nicht zu, werden die Anweisungen im Schleifenkörper nicht ausgeführt. Die Startbedingung muss also immer einen boolschen Wert (true | false) ergeben.
  • Zuletzt muss noch definiert werden in welchen Intervallen gezählt wird: i++. Die Schleife zählt also in Schritten von 1 nach oben bzw. addiert nach jedem Schleifendurchlauf 1 auf die Zählervariable i.

Ablauf einer for-Schleife[Bearbeiten]

Nehmen wir folgende Schleife an:

for( int i=0; i < 3; i++ ){
	System.out.println( i );
}

Sie wird folgendermaßen durchlaufen:

  1. Start: Initialisierung der Zählervariable auf den Wert 0
  2. Prüfung der Startbedingung: i = 0 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
  3. Erster Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 0
  4. Hochzählen: Die Zählervariable wird um 1 erhöht: 0 + 1 = 1
  5. Prüfung der Startbedingung: i = 1 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
  6. Zweiter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 1
  7. Hochzählen: Die Zählervariable wird um 1 erhöht: 1 + 1 = 2
  8. Prüfung der Startbedingung: i = 2 ist kleiner als 3 ( i < 3 = true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
  9. Dritter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 2
  10. Hochzählen: Die Zählervariable wird um 1 erhöht: 2 + 1 = 3
  11. Prüfung der Startbedingung: i = 3 genauso groß wie 3 ( i < 3 = false ), also dürfen die Anweisungen des Schleifenkörpers nicht mehr ausgeführt werden

Verwendungszweck[Bearbeiten]

For-Schleifen sind nützlich um eine bekannte Anzahl an immer wiederkehrenden Anweisungen auszuführen. Klassisch hierfür dürfte das Auslesen der Werte eines Arrays mittels einer Schleife sein. Beispielsweise dürfte ohne Schleifen die Ausgabe von in einem Array enthaltenen Werten sehr mühsam für den Programmierer sein. Dies würde bei zehn Werten wie folgt aussehen:

// erzeugt ein Array mit zehn Integer-Werten
int[] einArray = { 1,2,3,4,5,6,7,8,9,10 };

System.out.println( einArray[0] );
System.out.println( einArray[1] );
System.out.println( einArray[2] );
System.out.println( einArray[3] );
System.out.println( einArray[4] );
System.out.println( einArray[5] );
System.out.println( einArray[6] );
System.out.println( einArray[7] );
System.out.println( einArray[8] );
System.out.println( einArray[9] );

Diese Aufgabe lässt sich mittels einer Schleife erheblich erleichtern:

// erzeugt ein Array mit zehn Integer-Werten
int[] einArray = new int[10];
// nun wird das Befüllen des Arrays ebenfalls durch eine Schleife realisiert
for(int i=0; i < einArray.length; i++){
        einArray[i] = i + 1;
}

// For-Schleife, die die im Array enthaltenen Werte ausgibt
for( int i=0; i < einArray.length; i++ ){
	System.out.println( einArray[i] );
}

Mittels .length erhält man die Länge des Arrays als int-Wert. Somit lässt sich immer die Länge des Arrays bestimmen, auch wenn man diese zum Zeitpunkt der Programmierung noch nicht kennt.

Ein Array kann also mittels einer for-Schleife durchlaufen werden, da man einen Startwert = 0 sowie einen Endwert = .length hat. Da man alle Werte aus dem Array auslesen möchte (und nicht nur bestimmte), wird die Zählervariable immer um eins erhöht.

Im Schleifenkörper kann nun jeder Arrayplatz mit der Zählervariable angesprochen werden: einArray[i].

Innerhalb des Schleifenkörpers kann jede Art von Anweisung durchgeführt werden. Muss man beispielsweise eine größere Anzahl an Parametern nacheinander an ein und dieselbe Methode übergeben, kann man dies mittels einer Schleife tun:

// wiederholter Methodenaufruf in einer Schleife
for(int i=0; i < einArray.length; i++){
	eineMethode( einArray[i] );

	einObjekt.eineMethode( einArray[i] );
}

Es ist natürlich ebenfalls möglich mehrmals Objekte des gleichen Typs zu erstellen.

// ein Array zur Aufnahme von Objekten erzeugen
Integer[] einArray = new Integer[100];

// Befüllen des Arrays mit 100 Objekten vom Typ Integer
for( int i=0; i < einArray.length; i++ ){
	einArray[i] = new Integer( i );
}

Abkürzung[Bearbeiten]

Bei Arrays gibt es eine Kurzschreibweise, um über ein vorher belegtes Array zu iterieren:

int[] einArray  = {1, 2, 3};
for( int i : einArray ) {
      System.out.println(i);
}

Variationen[Bearbeiten]

Bei der Implementierung des Schleifenkopfes ist man nicht strikt an die in obigem Beispiel vorgestellte Form gebunden. Vieles ist möglich, solange man sich an die Syntax hält. Die folgenden Beispiele sollen nur kleine Anregungen sein.

// Bsp.: Initialisierung der Zählvariable
for( byte i = -120; i < 100; i++ ){
	System.out.println( i );
}	

int i = 50;
for(  ; i < 100; i++ ){
	System.out.println( i );
}

// Bsp.: Implementierung der Startbedingung
// Bsp.: abwärts zählen
for( int i = 150; i >= 100; i-- ){
	System.out.println( i );
}

// Bsp.: größeres Intervall
for( int i = 1; i <= 100; i+=10 ){
	System.out.println( i );
}
	
for( int i = 1; i <= 100; i*=2 ){
	System.out.println( i );
}

// Endlosschleife
for( ; ; ){
	System.out.println( 1 );
}

Schleife mit Vorabprüfung (while)[Bearbeiten]

Die while-Schleife führt den Anweisungsblock aus, solange die Prüfung true ergibt. Die Prüfung der Bedingung erfolgt dabei vor dem Betreten der Schleife. Beispiele

 while (true) {} // Endlosschleife
 int i = 0;
 while (i < 10) { i++; } // Ausführungsanzahl 10
 int i = 0;
 while (i < 0) {
   // wird nicht ausgeführt.
   System.out.println ("Come to me - PLEEEAAASE!");
 }

Schleife mit Nachprüfung (do)[Bearbeiten]

Die do-Schleife führt alle beinhalteten Anweisungen solange aus, wie die Prüfung true ergibt. Die Prüfung der Bedingung erfolgt dabei nach dem ersten Schleifendurchlauf. Zu einer do Schleife wird stets das Schlüsselwort while zur Bedingungsangabe benötigt. Beispiele

 do {} while (true); // Endlosschleife
 int i = 0;
 do { i++; } while (i < 10); // Ausführungsanzahl 10
 int i = 0;
 do {
   System.out.println("Thanx to come to me.");
 } while (i < 0);

Schleifen verlassen und überspringen (break und continue)[Bearbeiten]

Innerhalb einer do, while oder for-Schleife kann mit break die gesamte Schleife verlassen werden. Soll nicht die gesamte Schleife, sondern nur der aktuelle Schleifendurchlauf verlassen und mit dem nächsten Durchlauf begonnen werden, kann die Anweisung continue verwendet werden. Im folgenden Beispiel werden in einem Iterator über eine Personenkartei alle Personen gesucht, die zu einer Firma gehören. Dabei werden gesperrte Karteikarten übersprungen. Wird eine Person gefunden, die zu dieser Firma gehört und als Freiberufler tätig ist, wird die weitere Suche abgebrochen, da angenommen wird, dass ein Freiberufler der einzige Angehörige seiner Firma ist.

  String desiredCompany = "Wikimedia";
  Person[] persons;
  StringBuffer nameListOfWikimedia;
  
  for (int i=0;i<MAX_PERSONEN;i++) {
    if (persons[i].isLocked()) {
      continue; // Gesperrte Person einfach überspringen
    } 
    String company = persons[i].getCompany();
    if (company.equals(desiredCompany)) {
      nameListOfWikimedia.append(persons[i].getName());
      if (persons[i].isFreelancer()) {
        break; // Annahme: Ein Freelancer hat keine weiteren Mitarbeiter
      }
    }
  }

Diese Aussprünge ähneln den goto-Befehlen anderer Programmiersprachen, sind aber nur innerhalb der eigenen Schleifen erlaubt. Bei Schachtelung mehrerer Schleifen können diese auch mit Bezeichnern (Labels) versehen werden, so dass sich die break- oder continue-Anweisung genau auf eine Schleife beziehen kann:

  catalog: while(catalogList.hasNext()) {
    product: while (productList.hasNext()) {
      price: while (priceList.hasNext()) {
        [...]
        if (priceTooHigh) {
          continue product;
        }
      }
    }
  }

Übungen[Bearbeiten]

  1. Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die einfache Verzweigung.
  2. Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die Mehrfachverzweigung.
  3. Schreibe eine einfache Applikation, welche mit Hilfe der Zählschleife die Übergabeparameter ausgibt. Sofern du das JDK 1.5 oder höher verwendest nutze hierfür die alte und neue Variante.
  4. Wie oft wird die folgende do-Schleife ausgeführt und warum?
 int i = 10;
 do {
   i -= 3;
 } while (i > 5);