Träge Operandenstellen in Java
Der bedingte Oder-Operator »||«
Bei diesem Operator ist die erste Stelle strikt und die zweite träge.
Bedingte Auswertung
Der Operator »||« ist der erste Operator in diesem Kurs mit bedingter Auswertung (“lazy evaluation ”) eines Operanden. Diese ermöglicht es, mit dem linken Operanden zu steuern, ob der rechte Operand ausgewertet wird! So wird in dem folgenden Programm der Aufruf »f( 1 )« nicht ausgewertet.
Main.java
public final class Main
{
public static void eval( final boolean value ){} public static boolean f( final int v )
{ java.lang.System.out.println( "f( " + v + " )" ); return true; }
public static void main( final java.lang.String[] args )
{ eval( false || f( 0 ));
eval( true || f( 1 )); }}java.lang.System.out
f( 0 )
Bei der Ausführung der Methode »main« kommt es zu drei Operationen:
- Methodenoperation (der rechte Operand wird ausgewertet)
- —
false || f( 0 ) →
false || true- — Ausgabe von »f( 0 )«
- ||-Operation
- —
false || true →
true- —
- ||-Operation (der rechte Operand wird nicht ausgewertet!)
- —
true || f( 1 ) →
true- —
Striktheit und Trägheit
Man nennt eine Operandenstelle, die nur unter bestimmten Bedingungen ausgewertet wird, auch manchmal träge. Eine, die immer ausgewertet wird, heißt strikt. Wir können also sagen, daß bei dem Operator »||« die linke Stelle strikt ist, und die rechte träge.
Methodenparameter sind immer strikt. Das heißt, das es nicht möglich ist, eine Methode zu definieren, die eines ihrer Argumente nur unter bestimmten Bedingungen auswertet. Wenn ein Methodenaufruf ausgewertet wird, dann werden immer die Werte aller Argumentausdrücke bestimmt (auch wenn diese Werte von der Methode dann gar nicht verwendet werden). Es ist also nicht möglich, eine Methode mit zwei Parametern zu definieren, die sich so verhält, wie sich der Operator »||« verhält.
Der bedingte Oder-Operator »&&«
Bedingte Auswertung
Auch dieser Operator ermöglicht es, mit dem linken Operanden zu steuern, ob der rechte Operand ausgewertet wird. So wird in dem folgenden Programm der Aufruf »f( 0 )« nicht ausgewertet.
Main.java
public final class Main
{
public static void eval( final boolean value ){} public static boolean f( final int v )
{ java.lang.System.out.println( "f( " + v + " )" ); return true; }
public static void main( final java.lang.String[] args )
{ eval( false && f( 0 ));
eval( true && f( 1 )); }}java.lang.System.out
f( 1 )
Bei der Ausführung der Methode »main« kommt es zu drei Operationen:
- &&-Operation (der rechte Operand wird nicht ausgewertet!)
- —
false && f( 0 ) →
false- —
- Methodenoperation (der rechte Operand wird ausgewertet)
- —
true && f( 1 ) →
true && true- — Ausgabe des Textes »f( 1 )«
- &&-Operation
- —
true && true →
true- —
Die Methode »eval« (deutsch: „werte aus!“) hat weder einen Wert noch eine Wirkung, sie ist aber nötig, um die &&-Anwendungen auswerten zu lassen, denn da eine &&-Anwendung kein Anweisungsausdruck ist, darf sie nicht direkt als Ausdruck in einer Ausdruckanweisung stehen.
Das folgende Programmbeispiel zeigt Methodenaufrufe, die genau dann ein Sternchen ausgeben, falls ihr Argumentwert "true" ist.
Main.java
public final class Main
{ public static boolean sternchen()
{ java.lang.System.out.print( "*" ); return true; } public static boolean sternchen( final boolean i )
{ return i && sternchen(); } public static void main( final java.lang.String[] args )
{ java.lang.System.out.print( "true : " ); sternchen( true ); java.lang.System.out.println();
java.lang.System.out.print( "false: " ); sternchen( false ); java.lang.System.out.println(); }}java.lang.System.out
true : *
false:- Priorität und Assoziativität der bisher behandelten Operatoren
() Eingeklammerter Ausdruck
() Aufrufoperator
+ - Unaere vorangestellte Operatoren
L * / Multiplikation, Division
L + - Addition, Subtraktion
L && Und
L || Oder
R = Zuweisung, Anweisungsausdruck
Beispiel Bedingte Ausgabe
Mit dem &&-Operator können Methoden programmiert werden, die bisher so nicht programmiert werden konnten. Beispielsweise eine Methode zur Ausgabe der Wahrheitswerte in deutscher Sprache.
Main.java
public final class Main
{
public static void eval( final boolean value ){} public static boolean println( final java.lang.String text )
{ java.lang.System.out.println( text ); return true; } public static void println( final boolean value )
{ eval( value && println( "wahr" ));
eval( value || println( "falsch" )); } public static void main( final java.lang.String[] args )
{ println( false );
println( true ); }}java.lang.System.out
falsch
wahr
Beispiel Verneinung
Das folgende Beispiel zeigt die Implementierung einer Verneinung (aus true wird false und umgekehrt) mit Hilfe des bedingten Oder-Operators.
Main.java
public final class Main
{
public static void eval( final boolean value ){} public static boolean not( final boolean value )
{ boolean result = false;
eval( value ||( result = true ));
return result; } public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( not( false ));
java.lang.System.out.println( not( true )); }}java.lang.System.out
true
false
Die de Morgan schen Gesetze
Mathematische Schreibweise
- ¬( x ∨ y )⇔ ¬x ∧ ¬y
- ¬( x ∧ y )⇔ ¬x ∨ ¬y
Java -Schreibweise
- »!( x || y )« ⇔ »!x && !y«
- »!( x && y )« ⇔ »!x || !y«.
- Daraus folgt:
- »x || y« ⇔ »!( !x && !y )«.
- »x && y« ⇔ »!( !x || !y )«.
- (hierbei bedeutet „x ⇔ y “ „Die Auswertung von x hat dasselbe Verhalten wie die Auswertung von y “.)
Übungsfragen
Was gibt das folgende Programm aus?
Main.java
public final class Main
{ public static boolean t()
{ java.lang.System.out.print( "T " ); return true; } public static boolean f()
{ java.lang.System.out.print( "F " ); return false; } public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( t() && f() );
java.lang.System.out.println( f() && t() ); }}
Was gibt das folgende Programm aus?
Main.java
public final class Main
{ public static boolean t()
{ java.lang.System.out.print( "T " ); return true; } public static boolean f()
{ java.lang.System.out.print( "F " ); return false; } public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( t() || f() );
java.lang.System.out.println( f() || t() ); }}