Kurzeinstieg Java: Kontrollstrukturen
Wie funktioniert die bedingte Verzweigung?
[Bearbeiten]Verzweigungen ändern den linearen Programmfluss. In Abhängigkeit von einer Bedingung wird ein Programmteil ausgeführt – oder auch nicht. Verzweigungen werden mit if(bedingung) {etwas code}
erzeugt. Wenn sich die Bedingung zu true
auswerten lässt, dann wird der Programmcode im Block ausgeführt:
int zahl = 2;
if( zahl % 2 == 0 ) { // wenn die Zahl gerade ist ...
System.out.println("2 ist eine gerade Zahl"); // dann führe dieses aus, sonst nicht!
} // fertig
Im Fall, dass etwas zusätzlich ausgeführt werden soll, wenn die Bedingung nicht erfüllt ist, dann schreibt man das mit else
:
int zahl = 2;
if( zahl % 2 == 0 ) { // wenn die Zahl gerade ist ...
System.out.println(zahl + " ist eine gerade Zahl"); // dann führe dieses aus
}
else {
System.out.println(zahl + " ist ungerade."); // sonst führe dieses aus.
} // fertig
Die geschweiften Klammern kann man bei einzelnen Anweisungen übrigens weglassen.
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 Verzweigungen immer in geschweifte Klammern zu fassen. Dadurch lassen sich die einzelnen Ausdrücke besser dem jeweiligen if
zuordnen.
Was macht der Bedingungsoperator?
[Bearbeiten]Für manche Anwendungsfälle eignet sich der Bedingungsoperator ?:
. Sein Aufbau wird durch folgendes Programm verdeutlicht:
public class Testklasse {
public static void main(String[] args) {
int zahl = 4;
String geradeText = (zahl % 2 == 0) ? " gerade" : "ungerade";
System.out.println("Die Zahl " + zahl + " ist " + geradeText);
}
}
Dieser Operator wird zumeist in Ausdrücken benutzt, bei denen etwas zugewiesen wird. Wenn also eine Bedingung erfüllt ist, dann gib den ersten Teil als Ausdruck zurück, sonst den Teil, der hinter dem :
steht. Bedingungsoperatoren verwendet man überall dort, wo eine if
-else
-Konstruktion zu lang wäre.
Wie kann man lesbar vielfach verzweigen?
[Bearbeiten]if
-else
-Konstrukte kann man beliebig verschachteln. Bei einer Auswahl über sehr viele Kategorien werden solche Konstrukte schnell unübersichtlich. Hier kann switch
helfen. Diese Art der Mehrfachverzweigung können Sie nur mit ganzzahligen numerischen Typen (int
, byte
, short
), Zeichen (char
) und String
verwenden.
public class Testklasse {
public static void main(String[] args) {
String wochentag = "Montag";
switch( wochentag ) {
case "Montag":
case "Dienstag":
case "Mittwoch":
System.out.println("Die Woche nimmt kein Ende...");
break; // Bei Montag, Dienstag oder Mittwoch ist hier Schluss
case "Donnerstag":
System.out.println("Morgen ist schon Freitag");
break; // Nur bei "Donnerstag" ist hier Schluss
case "Freitag":
System.out.println("Endlich Freitag");
break;
default: // alle anderen Fälle
System.out.println("Endlich Wochenende!!!!!");
break;
} // Ende von switch()
}
}
Mit switch
wird die Auswahl getroffen, mit case
werden die einzelnen Fälle selektiert. Hat man Fälle, die man nicht im einzelnen explizit abfangen möchte, dann folgt default
.
Der Wert hinter case
muss eine Konstante sein und dient dem Vergleich mit dem übergebenen Wert (hier Montag
). 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.
Java in Versionen vor 7 erlaubten keine Variablen vom Typ String
.
For-each-Schleife
[Bearbeiten]Besonders im Zusammenhang mit Feldern ist eine for
-Schleife gebräuchlich, die über jedes Element des Arrays iteriert. "Für jedes Element eines Arrays mache folgendes...":
public class T {
public static void main(String[] args) {
int[] zahlen = {1, 2, 3, 4, 5, 6}; // Array
for(int zahl : zahlen) { // für jede Zahl im Array...
System.out.println(zahl + " ist eine sehr schöne Zahl."); // gib sie aus
}
}
}
Die Variable zahl
ist nur innerhalb der Schleife bekannt. Der Datentyp muss zum Datentyp der Feld-Elemente passen. Neben Arrays sind allgemeine Collection-Klassen (wir kommen später darauf zu sprechen) die Kernanwendungen dieser Schleife, die Oracle als "enhanced for statement" bezeichnet.
Allgemeine 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
- Bedingung mit Limitierung auf den Endwert. Ist diese Bedingung
true
dann wird die Zählschleife weiterhin ausgeführt - Schrittweite
- Schleifenkörper (Schleifenrumpf)
- Anweisungen, die pro Schleifendurchlauf ausgeführt werden sollen
Die Syntax
[Bearbeiten]Die grundlegende Syntax sieht folgendermaßen aus:
for( Initialisierung Zahlervariable; Limitierung; Zählen ){
...
Schleifenkörper mit Anweisungen
...
}
Beispiele:
for(int zahl = 1; zahl < 10; zahl++) { //
System.out.println(zahl);
}
In obigem Beispiel sieht man eine for-Schleife, die von 1 bis 9 zählt. Warum nur bis 9? Weil die Limitierung kleiner als 10 und nicht kleiner gleich 10 lautet.
- Zunächst muss eine Zählervariable auf einen Startwert initialisiert werden
int zahl=1
. Wird diese Variable im Schleifenkopf deklariert, ist sie ausschließlich im Schleifenkopf und im Schleifenkörper bekannt. Außerhalb der Schleife kann die Zählervariable nicht angesprochen werden.
- Dann wird die Limitierung for-Schleife festgelegt:
i < 10
. Sie läuft so lange wiezahl
kleiner als 10 ist. Trifft diese Bedingung nicht zu, werden die Anweisungen im Schleifenkörper nicht ausgeführt. Die Limitierung muss also immer einen boolschen Wert (true
oderfalse
) ergeben.
- Zuletzt muss noch definiert werden in welchen Intervallen gezählt wird:
zahl++
. Die Schleife zählt also in Schritten von 1 nach oben bzw. addiert nach jedem Schleifendurchlauf 1 auf die Zählervariablezahl
.
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:
- Start: Initialisierung der Zählervariable auf den Wert 0
- Prüfung der Limitierung: i = 0 ist kleiner als 3 ( i < 3 == true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
- Erster Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 0
- Hochzählen: Die Zählervariable wird um 1 erhöht: 0 + 1 = 1
- Prüfung der Limitierung: i = 1 ist kleiner als 3 ( i < 3 == true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
- Zweiter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 1
- Hochzählen: Die Zählervariable wird um 1 erhöht: 1 + 1 = 2
- Prüfung der Limitierung: i = 2 ist kleiner als 3 ( i < 3 == true ), also dürfen die Anweisungen des Schleifenkörpers ausgeführt werden
- Dritter Durchlauf: Die Zählervariable i wird am Bildschirm ausgegeben: 2
- Hochzählen: Die Zählervariable wird um 1 erhöht: 2 + 1 = 3
- Prüfung der Limitierung: 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 wiederkehrenden Anweisungen auszuführen. Sei es das Füllen eines Arrays, das Erzeugen einer gewissen Anzahl an Objekten oder die Ausgabe der ersten Zeilen einer Datenbankabfrage.
public class Testklasse {
public static void main(String[] args) {
// erzeugt ein Array mit zehn Integer-Werten
int[] einArray = new int[10];
// nun wird das Befüllen des Arrays ebenfalls durch eine Schleife realisiert
// es werden nur ungerade Zahlen ins Array gesteckt
for(int i = 0; i < einArray.length; i++) {
einArray[i] = 2 * i + 1;
}
// For-Schleife, die die im Array enthaltenen Werte ausgibt
for( int zahl : einArray ){
System.out.println( zahl );
}
}
}
Mittels .length
erhält man die Länge des Arrays als ganze Zahl. Somit lässt sich immer die Länge des Arrays bestimmen, das ist praktisch, man ist so weniger auf Konstanten angewiesen.
Ein Array kann also mittels einer for-Schleife durchlaufen werden, da man einen Startwert = 0 sowie einen Endwert = .length - 1
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]
.
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]; // Platz für 100 Objekte vom Typ Integer
// Befüllen des Arrays mit 100 Objekten vom Typ Integer
for( int i = 0; i < einArray.length; i++ ) {
einArray[i] = new Integer( 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 mit einer negativen Zahl
for( byte i = -120; i < 100; i++ ){
System.out.println( i );
}
int i = 50; // Bsp.: Variable für den Startwert außerhalb der Schleife festlegen
for( ; i < 100; i++ ){
System.out.println( i );
}
// 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 );
}
// Ausgabe aller 2er-Potenzen kleiner als 100
for( int i = 1; i <= 100; i*=2 ){
System.out.println( i );
}
// Endlosschleife
for( ; ; ){
System.out.println( "Hallo, Welt!" );
}
Schleife mit Vorabprüfung (while)
[Bearbeiten]Die while
-Schleife führt den Anweisungsblock aus, sofern die Bedingung im Schleifenkopf true
ergibt. Die Prüfung der Bedingung erfolgt dabei vor dem Betreten der Schleife. Beispiele
while (true) {} // Endlosschleife
int i = 0;
while (i < 10) { // Ausführungsanzahl 10
i++;
}
int i = 0;
while (i < 0) { // wird nicht ausgeführt.
System.out.println ("Schleifentest");
}
Kopfgesteuerte Schleifen werden benutzt, wenn man sich nicht sicher ist, ob eine Schleife überhaupt ausgeführt werden muss. Sie wird also "mindestens 0-mal" ausgeführt.
Einige Sortieraufgaben erfordern beispielsweise genau so ein Vorgehen: "Solange meine Sachen nicht sortiert sind, sortiere". Wenn die Sachen schon sortiert sind, braucht nichts sortiert und der Schleifenkörper braucht folglich nicht besucht zu werden.
Schleife mit Nachprüfung (do)
[Bearbeiten]Rumpfgesteuerte Schleifen sind quasi das Gegenstück zu kopfgesteuerten Schleifen. 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 ("Hallo, Welt!");
} while (i < 0);
Die do
-Schleife wird mindestens 1-mal ausgeführt.
Hier wird die do
-Schleife benutzt, um mit Bubblesort ein Array aufsteigend zu sortieren:
public class Testklasse {
public static void main(String[] args) {
// unsortiertes Array
int[] einArray = {10, 9, 8, 7, 6, 5, 4, 3, 2 };
int hilfsvariable;
boolean vertauscht;
do {
vertauscht = false;
for(int index = 0; index < einArray.length - 1; index++) {
if(einArray[index] > einArray[index + 1]) { // wenn falsche Reihenfolge
// vertausche 2 Nachbarn im Array
hilfsvariable = einArray[index];
einArray[index] = einArray[index + 1];
einArray[index + 1] = hilfsvariable;
// es wurde vertauscht
vertauscht = true;
} // ende von if
} // ende von for
} while (vertauscht); // weitermachen, so lange das Array unsortiert ist
// Array ausgeben
for(int elem : einArray) {
System.out.print( elem + " " );
}
System.out.println();
}
}
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]- Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die einfache Verzweigung.
- Schreibe ein einfaches Programm, welches für jeden Monat die Anzahl der Tage ausgibt. Nutze hierzu die Mehrfachverzweigung.
- 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.
- Wie oft wird die folgende
do
-Schleife ausgeführt und warum?
int i = 10; do { i -= 3; } while (i > 5);