9 Anweisungen und Kontrollstrukturen

Werbung
9
Anweisungen und Kontrollstrukturen
Hier beziehen wir uns auf Kapitel 6 von Go To Java 2.
Die Steuerung des Programmablaufs geschieht durch sogenannte Anweisungen.
Jede Anweisung bewirkt irgendwelche Aktionen des Prozessors. Einige Anweisungen haben Sie bereits kennengelernt, so ist z.B. die Verwendung der Ausgaberoutine eine Anweisung. Auch die Definition von Variablen oder die Verwendung
von Ausdrücken sind Anweisungen.
Jede Anweisung in einem Java–Programm muß mit einem Semikolon enden. Dies
ist nötig, da Zeilenumbrüche für den Java–Compiler keine Bedeutung haben und
er daher nicht anhand der Zeilenstruktur erkennen kann, wo eine Anweisung
zuende ist.
9.1
Leere Anweisung
Siehe auch Kapitel 6.1 in Go To Java.
Die einfachste Anweisung in einem Java–Programm ist die leere Anweisung.
Sie hat keine Wirkung. Daß die leere Anweisung erlaubt ist, bedeutet im wesentlichen, daß Sie beliebig viele Semikoli setzen dürfen — auch dort, wo nicht
unbedingt eines stehen muß.
Beispiel:
public class DemoEmpty {
public static void main( String[] args )
{
; // Leere Anweisung
;; // Zwei leere Anweisungen
}
}
9.2
Blockanweisung
Der Block gruppiert eine Gruppe von Anweisungen zu einer Einheit. Sie hat die
Form
{
Anweisung1;
Anweisung2;
...
}
Sie sollten sich angewöhnen, den Inhalt eines Blockes durch Einrückung der im
Block enthaltenen Zeilen optisch kenntlich zu machen — in allen Beispielprogrammen machen wir Ihnen das auch so vor.
Beachten Sie, daß die Beschreibung der Blockanweisung rekursiv ist — der Block
ist eine Anweisung und in einem Block dürfen wieder Anweisungen stehen. Daher darf in einem Block auch ein weiterer Block enthalten sein.
65
Beispiel: Dies ist ein gültiges Java–Programm. Im Klassenkörper ist die
Methode main enthalten. In deren Methodenkörper sind zwei ineinander
verschachtelte Blöcke enthalten.
Der Klassenkörper wird auch durch geschweifte Klammern abgegrenzt,
sieht also genauso aus wie ein Blöcke aus. Er ist aber dennoch kein Anweisungsblock, da er keine Anweisungen sondern nur Definitionen enthalten
darf.
public class DemoBlock { // hier startet der Klassenkörper
public static void main( String[] args )
{ // hier startet der Methodenkörper
; // Leere Anweisung
{ // hier startet Block 1
{ // und hier startet Block 2
System.out.println("Hallo, Welt !");
} // hier endet Block 2
} // hier endet Block 1
} // hier endet der Methodenkörper
} // hier endet der Klassenkörper
9.3
Variablendefinitionen
Variablendefinitionen haben wir schon oft benutzt. Sie wissen bereits, daß man
Variablen nur verwenden kann, nachdem man sie definiert hat.
Zu beachten ist, daß eine Variablen Variablendefinition immer nur für den Block
gilt, in welchem sie definiert wurde. Sobald die Programmausführung einen
Block verläßt, haben die in diesem Block definierten Variablen keine Bedeutung
mehr. Man sagt auch: Variablendefinitionen gelten nur lokal im enthaltenden Block.
Wenn in einem Block ein weiterer Block enthalten ist, erbt dieser alle Variablendefinitionen des äußeren Blockes:
Beispiel: Im folgenden Beispiel wird im Block 2 die Variable i1 definiert
und initialisiert. Da Block 3 und Block 4 in Block 2 enthalten sind, kann
i1 auch aus Block 3 und 4 verwendet werden.
Auch in Block A wird die Variable i1 definiert. Diese Variable i1 hat
gar nichts mit der Variable i1 in Block 2 zu tun, da sie außerhalb Block
2 definiert wurde. Die Variablendefinitionen von Block 2 und Block A
beeinträchtigen sich überhaupt nicht gegenseitig.
In Block 1 ist die Variable i1 nicht bekannt, da sie weder in Block 1 noch in
einem Block 1 umschließenden Block definiert wurde. Die Verwendung der
Variable i1 in Block 1 führt daher zu einer Fehlermeldung des Compilers.
public class DemoBlock1 {
public static void main( String[] args )
{ // Block 1
{ // Block 2
int i1 = 5;
{ // Block 3
{ // Block 4
System.out.println(i1);
66
}
}
}
{ // Block A
String i1 = "Hallo, Welt";
}
System.out.println(i1); // Fehler !
}
}
Sie dürfen in einem Block keine Variable zweimal definieren.
Beispiel: Das folgende Programm ist fehlerhaft, da die Variable i1 im
gleichen Block zweimal definiert wird:
public class DemoBlock2 {
public static void main( String[] args )
{
int i = 1;
double i = 3.5; //Fehler
}
}
Leider dürfen sich in Java Variablen nicht gegenseitig verdecken — sie dürfen
Variablen auch dann nicht in einem Block definieren, wenn sie zuvor nur in
einem diesen Block umschließenden Block definiert wurden.
Beispiel: Im folgenden Beispiel wird in Block 1 eine int–Variable definiert. Block 2 erbt diese Definition, da er in Block 1 enthalten ist. Daher
darf in Block 2 i nicht nochmal definiert werden.
public class DemoBlock3 {
public static void main( String[] args )
{ // Block 1
int i = 1;
{ // Block 2
int i = -5; // Fehler
}
}
}
9.4
Ausdrucksanweisungen
Zu den Ausführungen über Ausdrucksanweisunge in Kapitel 6.1 von Go To Java
2 braucht nichts hinzuzugefügt zu werden außer einem Beispiel:
Beispiel: Hier ein Beispiel mit verschiedenen Ausdrucksanweisungen.
01 public class DemoVar1 {
02 public static void main( String[] args )
03 {
04
System.out.println("Hallo, Welt !");
67
05
06
07
08
09 }
10 }
int i = 5;
i = 6;
i++;
5 + 2;
// Variablendefinition und Initialisierung
// Ausdrucksanweisung: Zuweisung
// Ausdrucksanweisung: Inkrement
//
In der Ausdrucksanweisung in Zeile 08 wird eine Addition durchgeführt.
Die Ausdrucksanweisung hat aber keine weitere Wirkung, da der Wert des
Ausdrucks weder ausgegeben noch sonstwie verwendet wird.
Die Ausdrücke in Zeile 06 und 07 haben dagegen eine Wirkung (nämlich
jeweils eine Veränderung der Variable i), da in ihnen Operatoren mit Nebeneffekten verwendet werden.
9.5
If–Anweisung
Kapitel 6.2 von Go To Java 2 sollte so verständlich sein. Nur fehlen mal wieder
Beispiele.
Sie sehen ja in Go To Java 2, daß eine if –Anweisung in zwei Versionen auftreten
kann. Einmal mit und einmal ohne else–Zweig. Beachten Sie bei der Besprechung
aller weiteren Anweisungen, daß eine Anweisung auch ein Block sein kann.
Beispiel: Hier ein Beispiel zu if
public class DemoIf1 {
public static void main( String[] args )
{
int temperatur = 30;
if ( temperatur > 25 )
System.out.println("Boah, ganz schön warm");
}
}
Beispiel: Hier ein Beispiel, bei welchem die Anweisung ein Block ist:
public class DemoIf2 {
public static void main( String[] args )
{
int temperatur = 30;
if ( temperatur > 25 ) {
System.out.println("Boah, ganz schön warm");
System.out.println("Stell doch mal einer die Klimaanlage an");
}
}
}
Beispiel: Und hier noch ein Beispiel, in dem es auch einen else–Zweig
gibt:
public class DemoIfElse {
public static void main( String[] args )
{
68
int temperatur = 30;
if ( temperatur > 22 ) {
System.out.println("Boah, ganz schön warm");
System.out.println("Stell doch mal einer die Klimaanlage an");
} else {
System.out.println("Schön --- zu heiß ist es nicht.");
}
}
}
Das in Go To Java erwähnte Dangling else (“hängendes Else”) bedarf noch einer
weiteren Diskussion: Sie sollten Dangling else—Strukturen immer vermeiden.
Verwenden Sie in Fällen, wo ein Dangling else auftritt, immer Blöcke !
Beispiel: Hier tritt ein Dangling else auf — aufgrund der suggestiven
Einrückung ist nicht auf den ersten Blick klar, daß die else–Anweisung
nicht zur ersten sondern zur zweiten if –Anweisung gehört. Das Programm
arbeitet daher nicht so, wie gewünscht.
public class DemoDangling1 {
public static void main( String[] args )
{
int temperatur = 30;
boolean istKlimaanlageAn = true;
if ( temperatur < 15 ) // if-Anweisung 1
if ( istKlimaanlageAn ) // if-Anweisung 2
System.out.println("Klimaanlage abstellen");
else
System.out.println("Schön --- zu kalt ist es nicht.");
}
}
Das Problem kann durch Verwendung von Blöcken behoben werden. Sie
sollten sich angewöhnen, in solchen leicht mißverständlichen Situationen
immer Blöcke zu verwenden !
public class DemoDangling2 {
public static void main( String[] args )
{
int temperatur = 30;
boolean istKlimaanlageAn = true;
if ( temperatur < 15 ) {
if ( istKlimaanlageAn )
System.out.println("Klimaanlage abstellen");
} else
System.out.println("Schön --- zu kalt ist es nicht.");
}
}
9.6
Switch–Anweisung
Die Switch–Anweisung ist in Go To Java in Kapitel 6.2.2 beschrieben.
69
Zur switch–Anweisung ist hinzuzufügen, daß hinter jedem case eine Reihe von
Anweisungen steht. Wird ein case angesprungen, so werden auch die darauf
folgenden case–Blöcke abgearbeitet, wenn kein break in den Anweisungen steht.
Beispiel: Das folgende Programm gibt die textliche Darstellung einer
Zahl aus. Dastut es einmal mit einer Folge von if –Anweisungen und einmal
mit einer gleichwertigen switch–Anweisung.
Tippen Sie das Programm ab und testen Sie, was passiert, wenn Sie einige
break–Anweisungen entfernen !
public class DemoSwitch {
public static void main( String[] args )
{
int zahl = 1;
if ( zahl == 1) {
System.out.println("Eins");
} else if (zahl == 2) {
System.out.println("Zwei");
} else if ( zahl == 3) {
System.out.println("Drei");
} else if (zahl == 4) {
System.out.println("Vier");
} else {
System.out.println("Diese Zahl kenne ich nicht");
}
// Äquivalente Lösung per switch:
switch(zahl) {
case 1:
System.out.println("Eins");
break;
case 2:
System.out.println("Zwei");
break;
case 3:
System.out.println("Drei");
break;
case 4:
System.out.println("Vier");
break;
default:
System.out.println("Diese Zahl kenne ich nicht-");
break;
}
}
}
9.7
Schleifen
Zu Kapitel 6.3 ist nicht viel hinzuzufügen außer einigen Beispielen.
9.7.1
Die While–Schleife
Die While–Schleife können Sie immer dann einsetzen, wenn Sie eine oder mehrere Anweisungen immer wieder ausführen wollen, solange eine gewisse Bedingung
erfüllt ist.
Sie hat die Form
while( Schleifenbedingung )
anweisung;
70
Der Anweisungsblock einer while–Anweisung wird immer wieder abgearbeitet,
während die Schleifenbedingung erfüllt ist.
Im Detail wird eine while–Anweisung wie folgt abgearbeitet: Zunächst wird die
Schleifenbedingung ausgewertet, welche ein boolscher Ausdruck sein muß. Falls
sich hier der Wert false ergibt, so wird mit der nächsten Anweisung hinter der
while–Schleife weitergemacht.
Falls sich hingegen für die Schleifenbedingung der Wert true ergibt, so wird
die Schleifenanweisung durchgeführt. Beachten Sie, daß diese Anweisung auch
ein Block sein darf. Nachdem die Schleifenanweisung abgearbeitet ist, wird die
Schleifenbedingung erneut geprüft, wenn sich hier wieder der Wert true ergibt,
wird die Schleifenanweisung erneut ausgeführt. Dies geschieht wieder und wieder, bis die Schleifenbedingung den Wert false ergibt.
Beispiel: Die Anweisung in Zeile 05 wird niemals ausgeführt, da die
Schleifenbedingung in Zeile 04 immer false ist.
01 public class DemoWhile1 {
02 public static void main( String[] args )
03 {
04
while( false )
05
System.out.println("Hallo, Welt");
06 }
07 }
Beispiel: Eine Schleife, die immer wieder ausgeführt wird und niemals
wieder verlassen wird, nennt man Endlosschleife. Das folgende Programm ist eine solche, da die Bedingung in Zeile 04 immer true ist.
Dieses Programm beendet sich nie, nachdem Sie es gestartet haben. Es
gibt wieder und wieder “Hallo, Welt” aus. Sie können es auf die harte
Tour unterbrechen, indem Sie die Tastenkombination Ctrl+c bzw. Strg+c
verwenden.
01 public class DemoWhile2 {
02 public static void main( String[] args )
03 {
04
while( true )
05
System.out.println("Hallo, Welt");
06 }
07 }
Beispiel: Das folgende Programm gibt die Zahlen von 1 bis 10 auf den
Bildschirm aus. Es verwendet dazu eine Zählervariable. Es demonstriert
außerdem, daß die Schleifenanweisung auch ein Block sein kann.
01 public class DemoWhile3 {
02 public static void main( String[] args )
03 {
04
int i = 1;
04
while( i <= 10 ) {
05
System.out.println(i);
06
i++;
07
}
07 }
08 }
71
Man könnte das obige Programm auch noch kompakter schreiben, indem
man den Inkrement–Operator in den Ausgabe–Befehl schreibt:
01 public class DemoWhile4 {
02 public static void main( String[] args )
03 {
04
int i = 1;
04
while( i <= 10 )
05
System.out.println(i++);
06 }
07 }
Eine weitere Variante des vorigen Programmes ist lehrreich. Wir können
die Variable i auch innerhalb der Schleifenbedingung inkrementieren. Dabei müssen wir aber darauf achten, daß die Schleifenbedingung schon vorm
ersten Durchlauf der Schleife einmal ausgeführt wird.
Auch das folgende Programm gibt die Zahlen 1 bis 10 aus. Machen Sie sich
das klar ! Achten Sie vor allem darauf, daß nun in der Schleifenbedingung
ein echtes kleiner und nicht ein kleiner–gleich–Zeichen steht.
01 public class DemoWhile4 {
02 public static void main( String[] args )
03 {
04
int i = 0;
04
while( i++ < 10 )
05
System.out.println(i);
06 }
07 }
9.7.2
Die Do–Schleife
Die do–Schleife arbeitet so ähnlich wie die while–Schleife. Sie hat die Form
do
anweisung;
while ( Schleifenbedingung );
Sie unterscheidet sich von der while–Schleife dadurch, daß der Schleifenkörper
in jedem Fall mindestens einmal durchlaufen wird.
Genau wie bei der while–Schleife wird nach jedem Durchlauf des Schleifenkörpers
die Schleifenbedingung geprüft. Immer wenn die Bedingung true ergibt, wird die
Schleife erneut durchlaufen.
Beispiel: Im folgenden Programm wird der Schleifenkörper genau einmal
durchlaufen und dabei “Hallo, Welt” ausgegeben. Da die Schleifenbedingung immer false ist, wird die Schleife danach nicht weiter ausgeführt.
01 public class DemoDo1 {
02 public static void main( String[] args )
03 {
04
do
72
05
06
07 }
08 }
System.out.println("Hallo, Welt");
while( false );
Beispiel: Im folgenden Programm wird der Schleifenkörper immer wieder einmal durchlaufen und dabei “Hallo, Welt” ausgegeben, da Schleifenbedingung immer true ist. Das Programm unterscheidet sich im Resultat
nicht von der vorhin besprochenen while–Endlosschleife.
01 public class DemoDo2 {
02 public static void main( String[] args )
03 {
04
do
05
System.out.println("Hallo, Welt");
06
while( true );
07 }
08 }
Beispiel: Das folgende Programm gibt die Zahlen von 1 bis 10 aus.
Beachten Sie den feinen Unterschied zum äquivalenten Programm mit
while–Schleife (class DemoWhile4) aus dem vorigen Abschnitt. Machen
Sie sich klar, warum hier nicht mit i=0 sondern mit i=1 begonnen wird.
01 public class DemoWhile4 {
02 public static void main( String[] args )
03 {
04
int i = 1;
04
do {
05
System.out.println(i);
06
} while ( i++ < 10 );
07 }
07 }
Man kann while– in do–Schleife ineinander umschreiben. Eine do–Schleife der
Form
do
anweisung;
while( Schleifenbedingung );
kann als while–Schleife äquivalent so geschrieben werden:
anweisung;
while ( Schleifenbedingung )
anweisung;
Eine while–Schleife der Form
while ( Schleifenbedingung )
anweisung;
kann als äquivalente do–Schleife so geschrieben werden:
73
if ( Schleifenbedingung ) {
do
anweisung;
while( Schleifenbedingung);
}
9.7.3
Die For–Schleife
Die For–Schleife ist die wohl am häufigsten verwendete Schleife. Während die
while– und do–Schleife meist dann eingesetzt werden, wenn man beim Beginn
der Schleifenabarbeitung noch nicht genau sagen kann, wie oft die Schleife durchlaufen werden soll, setzt man die for–Schleife meist dann ein, wenn man schon
vor Beginn der Schleife weiß, wie oft die Schleife durchlaufen werden soll. Meist
wird die for–Schleife dazu eingesetzt, eine Variable einen gewissen Wertebereich
durchlaufen zu lassen.
Sie hat die Form
for (init; test; update)
anweisung;
In den runden Klammern hinter dem for–Befehl werden drei durch Semikoli
getrennte Ausdrücke erwartet.
Wie eine for–Schleife arbeitet, wird am besten klar, indem wir sie in eine äquivalente while–Schleife umschreiben. Die for–Schleife kann man als Abkürzung
für die folgende Schleife interpretieren:
init;
while( test) {
anweisung;
update;
}
Der erste Teil in den runden Klammern (init) wird vor dem Start der Schleife
ausgewertet. Er dient meist dazu, in der Schleife benötigte Variablen zu definieren oder zu initialisieren.
Folgende Anweisungen und Ausdrücke sind hier erlaubt:
• “init” darf ein Ausdruck sein, wie in folgendem Beispiel:
for( i=0; i < 10; i++)
System.out.println(i);
• “init” darf eine Liste von Ausdrücken sein, die dann durch Kommata getrennt sein müssen, wie in diesem Beispiel:
for(i=0, j=0 ; i < 10; i++, j+=i ) {
System.out.println(i);
System.out.println(j);
}
• “init” darf eine Variablendefinition sein:
74
for(int i=0 ; i < 10; i++)
System.out.println(i);
Eine so definierte Variable ist nur innerhalb der for–Anweisung gültig.
Daher ist der folgende Programmtext gültiger Java–Code:
for(int i=0 ; i < 10; i++)
System.out.println(i);
for(double i=0.5 ; i < 10.5; i++)
System.out.println(i);
• “init” darf leer sein:
for( ; false; ) ;
Der zweite Ausdruck (test–Ausdruck) muß boolschen Datentyp haben. Er wird
ausgewertet, um zu prüfen, ob die Schleife durchlaufen werden soll. Während
der test–Ausdruck true ergibt, wird die Schleifenanweisung immer wieder ausgeführt.
Nach jedem Ausführen der Schleifenanweisung wird der update–Teil in den
runden Klammern ausgewertet. Dabei darf “update” ein Ausdruck oder eine
durch Kommata getrennte Liste von Ausdrücken sein (siehe Beispiele oben).
Im “update”–Teil werden meist mit Hilfe von Inkrement–Operatoren Variablen
verändert. Der update–Ausdruck darf leer sein.
Beispiel: Das folgende Programm gibt die Zahlen von 1 bis 10 aus.
01 public class DemoFor1 {
02 public static void main( String[] args )
03 {
04
int i;
05
for(i=1 ; i <= 10 ; i++ )
06
System.out.println(i);
07 }
08 }
Beispiel: Auch das folgende Programm gibt die Zahlen von 1 bis 10 aus.
Es empfiehlt sich, die Variablendefinition in die Initialisierungsanweisung
zu schreiben.
01 public class DemoFor2 {
02 public static void main( String[] args )
03 {
04
for(int i=10 ; i <= 100 ; i+=10 )
05
System.out.println(i / 10 );
06 }
07 }
Beispiel: Das folgende Programm gibt die Zahlen von 1 bis 10 rückwärts
aus:
75
01 public class DemoFor3 {
02 public static void main( String[] args )
03 {
04
for(int i=10; i > 0 ; i-- )
05
System.out.println(i);
06 }
07 }
Beispiel: In diesem Programm wird die Anweisung in Zeile 05 niemals
ausgeführt, da die Schleifenbedingung in Zeile 04 immer false ist.
01 public class DemoFor4 {
02 public static void main( String[] args )
03 {
04
for( ; false ; )
05
System.out.println("Hallo, Welt");
06 }
07 }
Beispiel: Dies ist eine Endlosschleife, da die Schleifenbedingung immer
true ist — es wird immer wieder der Text “Hallo, Welt” ausgegeben.
01 public class DemoFor5 {
02 public static void main( String[] args )
03 {
04
for( ; true ; )
05
System.out.println("Hallo, Welt");
06 }
07 }
Beispiel: Oft verschachtelt man mehrere Schleifen ineinander. Das folgende Programm gibt eine dreieckige Figur aus. Dazu verwenden wir die
Methode “System.out.print”. Diese arbeitet genauso wie die “println”–
Methode, beginnt aber nicht nach jeder Ausgabe mit einer neuen Zeile
sondern gibt aufeinanderfolgende Ausgaben hintereinander in der gleichen
Zeile aus.
01 public class DemoFor6 {
02 public static void main( String[] args )
03 {
04
for(int i=1 ; i <= 10 ; i++ ) {
05
for(int j = 1; j <= i ; j++ ) {
06
System.out.print("*");
07
}
08
System.out.println(); // neue Zeile beginnen
09
}
10 }
11 }
Beispiel: Sie können in einer for–Schleife beliebige Variablen als Kontrollvariablen verwenden, nicht nur int–Variablen. Wir demonstrieren hier
außerdem die Verwendung mehrerer Update–Ausdrücke.
Das Programm gibt 6–Mal die Zahl 5.0 aus.
76
public class DemoFor7 {
public static void main( String[] args )
{
int i = 5;
for(double d=0 ; d <= 5 ; d++, i-- ) {
System.out.println(d + i);
}
}
}
9.7.4
break und continue
Bitte lesen Sie die Ausführungen zu break und Continue in Go To Java, Kapitel
6.3 nach.
77
9.8
Zusammenfassung
Sie müssten nun die folgenden Fragen beantworten können:
⊲ Was ist ein Block ?
⊲ Wieso darf man in Java auch mehr als ein Semikolon zum Abschluß
eines Befehls verwenden ?
⊲ Was für einfache Anweisungen kennen Sie ?
⊲ Erklären Sie, wo eine einmal definierte Variable überall verwendet werden darf — was ist ihr Gültigkeitsbereich ?
⊲ Können sich Variablendefinitionen in Java gegenseitig verdecken ?
⊲ Nennen Sie Beispiele für Ausdrucksanweisungen !
⊲ Welche Beziehung gibt es zwischen Variablendefinitionen und
Blöcken ?
⊲ Was ist ein Dangling Else ?
⊲ Wie kann man ein Dangling Else vermeiden ?
⊲ Welche Schleifen kennen Sie ?
⊲ Wie werden do–Schleifen aufgebaut ?
⊲ Wodurch unterscheiden sich do und while–Schleife ?
⊲ Was ist eine Endlosschleife ?
⊲ Wie kann man ein Programm unterbrechen, das in einer Endlosschleife
hängt ?
⊲ Geben Sie ein Beispiel für eine Endlosschleife !
⊲ Wie kann man eine Do in eine While–Schleife umschreiben ?
⊲ Wie kann man eine While– in eine Do–Schleife umschreiben ?
⊲ Wie kann man eine for–Schleife in eine while–Schleife umschreiben ?
⊲ Wie muß eine For–Schleife aufgebaut sein ?
⊲ Wie kann der init–Teil einer For–Schleife aussehen ?
⊲ Wenn eine for–Schleife verwendet wird, um eine Variable einen gewissen Zahlenbereich durchlaufen zu lassen — wo sollte diese Variable
definiert werden ?
⊲ Schreiben Sie ein Programm, das rückwärts von 10 bis 1 zählt – einmal
mit einer do–Schleife, einmal mit einer for– und einmal mit einer while–
Schleife.
78
Herunterladen