Die Ausführungswahl
Syntax der Ausführungswahl (vereinfacht)
else (englisch) /ɛls/ „sonst“
- Die Ausführungswahl (eine Möglichkeit der Syntaxbeschreibung)
.------------------------. .-''-. .-----------.
--->| if-Anweisung ohne else |--->( else )--->| Anweisung |--->
'------------------------' '-..-' '-----------'- Die Ausführungswahl (alternative Variante der Syntaxbeschreibung)
.--. .--. .----------. .--. .-----------. .-''-. .-----------.
--->( if )--->( ( )--->| Ausdruck |--->( ) )--->| Anweisung |--->( else )--->| Anweisung |--->
'--' '--' '----------' '--' '-----------' '-..-' '-----------'- Die Ausführungswahl (mit sprechenden Bezeichnungen)
.--. .--. .-----------. .--. .------------. .-''-. .-------------.
--->( if )--->( ( )--->| Bedingung |--->( ) )--->| Konsequenz |--->( else )--->| Alternative |--->
'--' '--' '-----------' '--' '------------' '-..-' '-------------'
Die Ausführungswahl wird auch if-Anweisung oder Verzweigung genannt. Ihr beiden Anweisungen bezeichnet man auch als Zweige dieser Anweisung.
Der Unterschied zur bedingten Anweisung besteht in der else-Klausel am Ende. (Eine Klausel ist ein Teil eines Programms, der durch ein Schlüsselwort eingeleitet wird, welches die Bezeichnung der Klausel festlegt.)
Wenn man von einer if-Anweisung spricht, kann sowohl eine bedingte Ausführung (ohne »else«) als auch eine Ausführungswahl (mit »else«) gemeint sein.
Typanforderungen
Der Ausdruck muß den Typ »boolean« haben.
Schlüsselwörter
»else« ist ein Schlüsselwort.
Die bisher behandelte Schlüsselwörter
- »boolean«, »double«, »else«, »if«, »public«, »return«, »int«, »final«, »static«, »void«
Semantik der Ausführungswahl (vereinfacht)
Bei der Ausführung einer Anweisung dieser Art wird zunächst der Ausdruck ausgewertet.
Die erste Anweisung wird genau dann ausgeführt, wenn der Ausdruck true ist, sonst (englisch “else ”) wird die zweite Anweisung ausgeführt.
Der Ausdrück wählt also aus, welche der beiden Anweisungen ausgeführt wird.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ if( true )java.lang.System.out.println( "0 true" );
else java.lang.System.out.println( "0 false" );
if( false )java.lang.System.out.println( "1 true" );
else java.lang.System.out.println( "1 false" ); }}java.lang.System.out
0 true
1 false
Vergleich mit der Auswertungswahl
Die Auswertungswahl mit »?« und »:« akzeptiert zwei Ausdrücke, die Ausführungswahl akzeptiert zwei Anweisungen. Beim obigen Beispiel unterscheiden sich die Anweisungen nur in den Ausdrücken, so daß die Verwendung der Auswertungswahl hier eine kürzere Formulierung mit weniger Wiederholungen erlaubt.
Man kann die Auswertungswahl auch als „ein if für Ausdrücke“ ansehen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args)
{ java.lang.System.out.println( true ? "0 true" : "0 false" );
java.lang.System.out.println( false ? "1 true" : "1 false" ); }}java.lang.System.out
0 true
1 false
Eine return-Anweisung kann beispielsweise nicht direkt als Operand in einem »?«-»:«-Operator verwendet werden, da sie eine Anweisung und kein Ausdruck ist. Sie muß in einer if-Anweisung stehen.
Umgekehrt kann eine if-Anweisung nicht direkt als Rückgabeausdruck in einer return-Anweisung verwendet werden. Hier ist ein »?«-»:«-Operator nötig.
Initialisierung von Variablen
Eine Java -Implementation stellt sicher, daß benutzte Variablen oder Konstanten initialisiert sind. Dabei ist es gestattet, die Initialisierung erst nach der Deklaration vorzunehmen, solange schon beim Übersetzen erkannt werden kann, daß die Initialisierung auf jeden Fall vor der ersten Benutzung erfolgt sein wird.
Das nächste Programm zeigt Fälle, in denen die Java -Implementation schon bei der Übersetzung erkennen kann, daß alle vorkommenden Konstanten vor ihrer ersten Benutzung (Auslesung) initialisiert wurden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{{ final int k;
k = 0;
java.lang.System.out.println( k ); }{ final int k;
if( java.lang.Math.random() > 0.5 )k = 0;
else k = 1;
java.lang.System.out.println( k ); }{ final int k;
if( true )k = 0;
java.lang.System.out.println( k ); }{ final int k;
if( 1 + 1 == 2 )k = 0;
java.lang.System.out.println( k ); }}}java.lang.System.out
0
0
0
0
Das nächste Programm zeigt einen Fall, in dem die Java -Implementation bei der Übersetzung nicht erkennen kann, daß alle vorkommenden Konstanten vor ihrer ersten Benutzung (Auslesung) initialisiert wurden. (Dies trifft ja auch tatsächlich nicht zu.)
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final int k;
if( java.lang.Math.random() < 0.5 )k = 0;
java.lang.System.out.println( k ); }}- Konsole
Main.java:5: error: variable k might not have been initialized
java.lang.System.out.println( k ); }}
^
return -Anweisungen *
Wie eine bedingte Ausführung, kann auch eine Verzweigung Rückgabeanweisungen enthalten.
Das folgende Beispiel wird von einer Java -Implementation akzeptiert, da diese erkennen kann, daß k immer dann initialisiert wird, wenn es auch später ausgelesen wird.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final int k;
if( java.lang.Math.random() < 0.5 )return; else k = 0;
java.lang.System.out.println( k ); }}
Verschachtelte Verzweigungen
Eine Anweisung, die Teil einer if -Anweisung ist, kann ihrerseits auch selber wieder eine if -Anweisung sein.
Folgte ein »else« auf zwei »if«, so kann es Situationen geben, in denen es nicht klar ist, zu welchem der beiden »if« das »else« gehört. Es gehört dann zum zweiten »if«, also zu dem »if«, welches dem »else« am nächsten ist.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ if( true )if( false )java.lang.System.out.println( "1" );
else java.lang.System.out.println( "2" ); }}java.lang.System.out
2
Soll das »else« statt dessen zum ersten »if« gehören, so kann dies durch entsprechende Klammerung erreicht werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ if( true ){ if( false )java.lang.System.out.println( "1" ); }
else java.lang.System.out.println( "2" ); }}java.lang.System.out
- keine Ausgabe
if -Kaskaden
if -Kaskaden lassen sich an der typischen Folge »else if« erkennen. Dabei handelt es sich aber um nichts anderes als eine Verschachtelung normaler if -Anweisungen. Sie werden verwendet, wenn es insgesamt mehr als zwei Zweige geben soll.
Main.java
public final class Main
{public static java.lang.String deutsch( final int a )
{ final java.lang.String result;
if( a == 0 )result = "Null";
else if( a == 1 )result = "Eins";
else if( a == 2 )result = "Zwei";
else if( a == 3 )result = "Drei";
else result = "Vier";
return result; }public static void print( final int a )
{ java.lang.System.out.println( a + " ist " + deutsch( a )+ "." ); }public static void main( final java.lang.String[] args )
{ print( 0 ); print( 1 ); print( 2 ); print( 3 ); print( 4 ); }}java.lang.System.out
0 ist Null.
1 ist Eins.
2 ist Zwei.
3 ist Drei.
4 ist Vier.
Manchmal können solche Alternativen auch mit weniger »else« formuliert werden.
Main.java
public final class Main
{public static java.lang.String deutsch( final int a )
{ java.lang.String result = "Vier";
if( a == 0 )result = "Null";
if( a == 1 )result = "Eins";
if( a == 2 )result = "Zwei";
if( a == 3 )result = "Drei";
return result; }public static void print( final int a )
{ java.lang.System.out.println( a + " ist " + deutsch( a )+ "." ); }public static void main( final java.lang.String[] args )
{ print( 0 ); print( 1 ); print( 2 ); print( 3 ); print( 4 ); }}java.lang.System.out
0 ist Null.
1 ist Eins.
2 ist Zwei.
3 ist Drei.
4 ist Vier.
Bei der Formulierung ohne »else« werden aber wahrscheinlich zur Laufzeit mehr Bedingungen geprüft. Außerdem besteht das Risiko, daß sich die Anweisung auch nicht wie beabsichtigt verhält, wenn einer der Zweige eine Änderung vornimmt, welche eine Bedingung beeinflußt, dazu vergleiche man die folgenden beiden Programme.
Main.java
public final class Main
{
public static void print( int a )
{ if( a == 1 ){ java.lang.System.out.println( "Eins." ); a = 0; }
else if( a == 0 ){ java.lang.System.out.println( "nicht Eins." ); a = 1; }
else {} }
public static void main( final java.lang.String[] args )
{ print( 1 ); }}java.lang.System.out
Eins.
Main.java
public final class Main
{
public static void print( int a )
{ if( a == 1 ){ java.lang.System.out.println( "Eins." ); a = 0; }
if( a == 0 ){ java.lang.System.out.println( "nicht Eins." ); a = 1; }}
public static void main( final java.lang.String[] args )
{ print( 1 ); }}java.lang.System.out
Eins.
nicht Eins.
Dieses Beispiel zeigt, daß bei einer Mehrfachverzweigung im allgemeinen darauf geachtet werden sollte, die »else« nicht wegzulassen oder zu vergessen. Man kann es auch als eine Illustration der Probleme verstehen, die Variablen mit sich bringen, den das Beispiel wäre so nicht möglich, wenn a eine Konstante wäre. (Natürlich wurden die Zuweisung an a hier extra für dieses Beispiel in das Programm geschrieben, aber auch in der Praxis findet man vergleichbare Fälle, die aber für diese Lektion aber unnötig kompliziert wären.)
Das am Anfang dieses Abschnitts gezeigte Programm kann natürlich kürzer mit bedingten Auswertungen geschrieben werden.
In diesem Teil des Kurses ist es leider noch nicht einfach, Beispiele mit »else« zu finden, die sich nicht kürzer mit dem ternären Operator schreiben lassen.
Main.java
public final class Main
{public static java.lang.String deutsch( final int a )
{ return a == 0 ? "Null" : a == 1 ? "Eins" :
a == 2 ? "Zwei" : a == 3 ? "Drei" : "Vier"; }public static void print( final int a )
{ java.lang.System.out.println( a + " ist " + deutsch( a )+ "." ); }public static void main( final java.lang.String[] args )
{ print( 0 ); print( 1 ); print( 2 ); print( 3 ); print( 4 ); }}java.lang.System.out
0 ist Null.
1 ist Eins.
2 ist Zwei.
3 ist Drei.
4 ist Vier.
Refaktor Gleiche Anweisungen in beiden Zweigen *
Eine Anweisung, die in beiden Zweigen vorkommt, kann manchmal vor oder hinter die Verzweigung geschrieben werden.
- Vorher
if( b() ){ f(); g(); } else g();
- Hinterher
if( b() )f(); g();
- Vorher
if( b() ){ f(); g(); } else f();
- Nachher
f(); if( b() )g();
Es gibt noch weitere ähnliche Refaktoren dieser Art.
Übungsfragen
Übungsfrage
Was gibt das folgende Programm aus?
Main.java
public final class Main
{public static java.lang.String deutsch( final int a )
{ java.lang.String result;
if( a == 0 )result = "Null";
if( a == 1 )result = "Eins";
if( a == 2 )result = "Zwei";
if( a == 3 )result = "Drei";
else result = "Vier";
return result; }public static void print( final int a )
{ java.lang.System.out.println( deutsch( a )); }public static void main( final java.lang.String[] args )
{ print( 0 ); print( 1 ); print( 2 ); print( 3 ); print( 4 ); }}
Übungsfrage
Was gibt das folgende Programm aus?
Main.java
public final class Main
{public static void report( final int a )
{ if( a > 1 )java.lang.System.out.println( "a > 1" );
else if( a > 2 )java.lang.System.out.println( "a > 2" );
else if( a > 4 )java.lang.System.out.println( "a > 4" );
else if( a > 8 )java.lang.System.out.println( "a > 8" );
else java.lang.System.out.println( "else" ); }public static void main( final java.lang.String[] args )
{ report( 10 ); }}
Übungsfrage
Wie kann man die folgende Methodendeklaration verkürzen?
- Methodendeklaration
public static void test( final boolean x )
{ final boolean result;
if( x )result = true;
else result = false;
return result; }
Übungsfrage
- Die folgende Methodendeklaration, soll eine Methode deklarieren, die true genau dann ergibt, wenn x den Wert false hat.
static boolean isFalse( boolean x )
{ boolean result;
if( x = false )result = true;
else result = false;
return result; }
Wie kann man diese Methodendeklaration korrigieren?
Übungsaufgaben
/ Refaktor
Die folgende Methodendeklarationen enthält einige Wiederholungen von Ausgabeanweisungen. Verkürzen Sie diese Methodendeklaration – bei unverändertem Verhalten – , indem Sie einzelne dieser Ausgabeanweisungen entweder an eine andere Stelle im Quelltext verschiebt oder löschen.
- Methodendeklaration
public static void ausgabe( final int zahl )
{ if( zahl > 0 )
{ java.lang.System.out.println( "Die Zahl ist " );
java.lang.System.out.println( "positiv." ); }
else
{ java.lang.System.out.println( "Die Zahl ist " );
java.lang.System.out.println( "nicht " );
java.lang.System.out.println( "positiv." ); }}
/ Refaktor
Die folgende Methode gibt das Maximum zweier int-Werte zurück. Schreiben Sie sie so um, daß statt der if-Anweisung der ternäre Operator verwendet wird.
- Methode
public static int max( final int l, final int r )
{ if( l > r )return l; else return r; }
/ Refaktor
Teilen Sie die folgende Methodendeklaration – bei unverändertem Verhalten – auf drei Methodendeklaration auf, deren jede eine der if-Anweisungen enthält.
Eine dieser drei Methoden soll »onCreate« heißen und dasselbe Verhalten zeigen wie die unten gezeigte Methode »onCreate«, dazu kann sie die anderen beiden Methoden als Hilfsmethoden aufrufen.
- Methode
public final void onCreate()
{ if( packageManager.hasSystemFeature( android.content.pm.PackageManager.FEATURE_CAMERA ))
{ this.camera = android.hardware.Camera.open();
if( this.camera != null )
{ final android.hardware.Camera.Parameters cameraParameters = camera.getParameters();
if( cameraParameters != null )use( cameraParameters );
else fail( "Can't get camera parameters!" ); }
else fail( "Can't open camera!" ); }
else fail( "System feature camera not available on package manager!" ); }
Übungsaufgaben
/ Methoden zur Abkürzung/Weiterleitung
Ergänzen Sie das folgende Programm um die Deklaration einer Methode »pow« zur Potenzierung.
- Main.java
public final class Main
{ ...public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( pow( 2, 3 )); }}java.lang.System.out
8
/ Eine Zufallszahlenmethode
Schreiben Sie die Deklaration einer Wertmethode »wert0bis1«, so daß der Wert des Aufrufausdrucks »wert0bis1()« ein zufälliger double-Wert zwischen 0 und 1 ist. Diese Methode soll keine Wirkung haben.
/ Summen-Methode
Schreiben Sie eine int-Methode »sum« welche die Summe ihrer beiden Argumentwerte ergibt und berechnen Sie dann die Summe »2 + 3 + 5« mit Hilfe von Aufrufen dieser Methode (ohne den Operator »+«).