2.3 Operatoren und Ausdrücke

Ausdrücke

Ausdrücke in Java sind alles was einen Rückgabewert liefert:

  • Konstanten
  • Variablen
  • Methoden
  • Operatoren

Operatoren

Java verfügt über

  • unäre (einstellige, monadische) Operatoren
  • binäre (zweistellige, dyadische) Operatoren
  • einen dreistelligen (ternären, tryadischen) Operator (den Bedingungsoperator "_ ? _ : _")

 

Unäre Operatoren haben einen einzigen Operanden. Beispiele sind:

  • Vorzeichenoperator: -a
  • Postinkrement: a++
  • Negation: !a
Unärer Operator

 

Binäre Operatoren haben zwei Operanden. Beispiele sind:

  • Addition:  a + b
  • logischer Vergleich: a ==  b
Binaerer Operator

Arithmetische Operatoren

Die arithmetischen Operatoren können auf die folgenden Typen angewendet werden

  • byte
  • short
  • int
  • long
  • float
  • double
Zweistellige arithmetische Operatoren
Operator Beispiel Semantik
+ a + b Addition: Summe von a und b
- a - b Subtraktion: Differenz an a und b
* a * b Multiplikation: Produkt von a und b
/ a /  b Division: Quotient von a und b
% a % b Modulo: Rest einer ganzzahligen Division von a durch b

Die Division von Ganzzahlen ergibt immer ganzzahlige Ergebnisse!

Java arbeitet ohne eine Erkennung des Überlaufs der Wertebereiche. Der Entwickler muss selbst die entsprechenden Vorsichtsmaßnahmen ergreifen.

Weiterhin gibt es einstellige (unäre) arithmetische Operatoren

Unäre arithmetische Operatoren
Operator Beispiel Semantik
+ +a Der Wert von a bleibt erhalten (Idempotente Operation)
- -a Der Wert von a wird negiert
++

a++

++a

Postinkrement: Der Ausdruck behält ursprünglichen Wert . Der Wert von a wurde um 1 erhöht

Präinkrement: Der Wert von a wird um 1 erhöht und der Ausdruck erhält den erhöhten Wert von a

--

x--

--x

Postdekrement: Der Ausdruck behält ursprünglichen Wert . Der Wert von a wurde um 1 erniedrigt

Prädekrement: Der Wert von a wird um 1 erniedrigt und der Ausdruck erhält den verminderten Wert von a

Die folgen drei Anweisungen bewirken das gleiche:

a = a + 1;
a++;
++a;

Bei Inkrementen mit gleichzeitiger Zuweisung ergeben jedoch unterschiedliche Werte für den zugewiesenen Wert

Variante 1 Wert a Wert b Variante 2 Wert a Wert b

a = 10; b = 4;

b = a++;

10

11

4

10 (!)

a = 10; b = 4;

b = ++a;

10

11

4

11 (!)

Beispiel

Quellcode Konsolenausgabe
package s1.block2.skript;
public class PrePostFixTest {
    public static void main(String[] args) {
        int x = 10;
        int y = 100;
        System.out.println("x = " + x + "; y = " + y);
        x++;
        System.out.println("x++ results in " + x);
        ++x;
        System.out.println("++x results in " + x);
        System.out.println("Set x to 0 ");
        x=0;
        System.out.println("x = " + x + "; y = " + y);
        y=x++;
        System.out.println("y=x++ (Postfix)");
        System.out.println("x = " + x + "; y = " + y);
        y=++x;
        System.out.println("y=++x (Prefix)");
        System.out.println("x = " + x + "; y = " + y);
}
.
.
.
.
.
x = 10; y = 100
.
x++ results in 11
.
++x results in 12
Set x to 0
. 
x = 0; y = 100
.
y=x++ (Postfix)
x = 1; y = 0
.
y=++x (Prefix)
x = 2; y = 2
.

Arithmetik der Ganzzahlen

  • Alle Operationen auf Ganzzahlen ergeben wieder Ganzzahlen. Dies wird nicht unbedingt von der Division erwartet!
  • Versuche durch 0 (Null) zu dividieren lösen eine ArithmeticException Ausnahme aus.

Arithmetik der Fließkommazahlen

Bei der Arithmetik mit Fließkommazahlen werden im Gegensatz zu den Ganzzahlen Überläufe erkannt. Die Fließkommazahlen besitzen eine Reihe Konstanten:

Konstante Semantik
POSITIVE_INFINITY Positiv unendlich
NEGATIVE_INFINITY Negativ unendlich
MAX_VALUE Größter darstellbarer Wert
MIN_VALUE Kleinster darstellbarer Wert
NaN "Not a number" Dieser Wert ist ungleich zu allen anderen Werten im Wertebereich

 

Vergleichsoperatoren

Gleichheit bzw. Ungleichheit bezieht sich auf den Wert der Variablen x und y

Vergleichsoperatoren
Operator Beispiel Semantik (Bedeutung)
== x == y ist x gleich y ?
!= x != y ist x ungleich y ?
< x < y ist x kleiner als y ?
<= x <= y ist x kleiner oder gleich y ?
> x > y ist x größer als y ?
>= x >= y ist x größer oder gleich y ?

 

Logische Operatoren

Die logischen Operatoren wirken auf den Typ Boolean der nur den Wert wahr oder falsch kennt.

Logische Operatoren
Operator Beispiel Semantik (Bedeutung)
! !a Negation
& a & b Und
| a | b Oder (inklusiv)
^ a ^ b Entweder-Oder
&& a && b bedingt auswertendes Und
|| a || b bedingt auswertendes Oder

 

Bedingungsoperator

Der dreistellige (ternäre) Bedingungsoperator (Konditionaloperator) erlaubt eine Zuweisung von dem Ergebnis einer Bedingung abhängig zu machen. Er hat die Form:

<ausdruck1> ? <ausdruck2> : <ausdruck3>

ausdruck1 muss einen boolschen Wert ergeben. Wird ausdruck1 wahr, so wird ausdruck2 der entsprechenden Variable zugewiesen. Wird ausdruck1 unwahr, so wird der ausdruck3 zugewiesen

Hiermit kann man Zuweisungen wie die Folgende formulieren

int maximum;
int x = 1;
int y =2 ;
maximum = (x > y) ? x : y ;

Das Ergebnis ist 2, da y (=2) größer als x (=1) ist.

Bedingt auswertende logische && und || Operatoren

Die bedingt auswertenden Operatoren werten Terme nur soweit aus bis das Endergebnis fest steht. Dies macht sie sehr effizient.

Im Beispiel:

boolean a = ((1<3) || (4>5));

wird der Term (4>5) nicht mehr ausgewertet. Da (1<3) wahr ist, steht das Endergebnis schon fest.

Die bedingt auswertenden logischen Operatoren wendet man neben Ihrem Geschwindigkeitsvorteil auch gerne an um potentielle Fehler und Ausnahmen zu vermeiden.

Ein Beispiel hierfür ist:

if ((a>0) && (Math.sqrt(a)>2))

Die Wurzel wird nur ausgewertet wenn a größer als Null ist.

Vorsicht: Durch die bedingte Auswertung können unterschiedliche Ergebnisse enstehen wenn in einem Ausdruck gleichzeitig ein Wert verändert wird!

Beispiel:

  bedingter "Oder" Operator einfacher "Oder" Operator
Quellcode
public static void t1() {
   int a = 3;
   int b = 5;
   if ((a>1) || (a<b++)){
      System.out.println ("Hallo");
   }
   System.out.println("b= " + b);
}
public static void t2() {
   int a = 3;
   int b = 5;
   if ((a>1) | (a<b++)){
      System.out.println ("Hallo");
   }
   System.out.println("b= " + b);
}
Ausgabe
Hallo
b= 5
Hallo

b= 6

Das Postinkrement (b++) in der linkten bedingten oder Bedingung wird nicht ausgeführt, da der Ausdruck (a>1) schon wahr geworden ist.

Bitoperatoren

Mit Bitoperatoren werden alle Bits einer Variablen einzeln manipuliert.

Bitoperatoren
Operator Beispiel Bedeutung
~ ~a Komplement
& a & b Und
| a | b Oder
^ a ^b exklusives Oder

Beispiel

package s1.block2.skript;
public class BitOperator {
    public static void main(String[] args) {
        int a = 7;
        int b = 6;
        int result;

        result = a & b;
        System.out.println("a = " + a + "; b = " + b + " result = " + result);

        result = a | b;
        System.out.println("a = " + a + "; b = " + b + " result = " + result);

        result = a ^ b;
        System.out.println("a = " + a + "; b = " + b + " result = " + result);
    }
}

Ergebnis

a = 7; b = 6 result = 6
a = 7; b = 6 result = 7
a = 7; b = 6 result = 1

Erklärung

result = a & b
Variable Dezimal Binär
a 7 0 0000000 00000000 00000000 00000111
b 6 0 0000000 00000000 00000000 00000110
result = a & b 6 0 0000000 00000000 00000000 00000110
result = a | b
Variable Dezimal Binär
a 7 0 0000000 00000000 00000000 00000111
b 6 0 0000000 00000000 00000000 00000110
result = a | b 7 0 0000000 00000000 00000000 00000111

Bitschiebeoperatoren 

Bitschiebeoperatoren

Operator

Beispiel Bedeutung
<< a << b Wert des Ausdrucks sind die Bits von a die um b Positionen nach links verschoben wurden. Es wird mit 0 Bits aufgefüllt.
>> a >> b Wert des Ausdrucks sind die Bits von a  die um b Positionen nach rechts verschoben wurden. Es wird mit dem höchsten Bit aufgefüllt.
>>> a >>> b Wert des Ausdrucks sind die Bits von a die um b Positionen nach rechts verschoben wurden. Es wird mit dem "0" Bits aufgefüllt.

Das kleine Programm rechts erlaubt die drei Bitschiebeoperationen zu testen.

Es kann die Bits um jeweils eine Stelle verschieben.

Hier die jar Datei herunterladen.

Das Programm dann mit dem Kommandozeilenbefehl:

java -jar IntShiftApplet.jar

Es erscheint ein Fenster wie folgt:

 Bild des IntShiftApplet

Quellcode des Applets und Anleitung zum Starten als Javaprogramm von der Konsole.

Beispiel

package s1.block2.skript;
public class ShiftingBits {
    public static void main(String[] args) {
        int x = 4;
        int result;
        int shift = 1;

        result = x << shift;
        System.out.println("x = " + x + "; shift = " + shift + " result = " + result);

        result = x >> shift;
        System.out.println("x = " + x + "; shift = " + shift + " result = " + result);

        result = result >> shift;
        System.out.println("x = " + x + "; shift = " + shift + " result = " + result);

        result = result >> shift;
        System.out.println("x = " + x + "; shift = " + shift + " result = " + result);

        result = result >> shift;
        System.out.println("x = " + x + "; shift = " + shift + " result = " + result);
    }
}

Ergebnis


 
x = 4; shift = 1 result = 8
x = 4; shift = 1 result = 2
x = 4; shift = 1 result = 1
x = 4; shift = 1 result = 0
x = 4; shift = 1 result = 0

Die interne Darstellung der verwendeten Werte:

Binäre Darstellung
Dezimalwert Binärwert
8 0 0000000 00000000 00000000 00001000
4 0 0000000 00000000 00000000 00000100
2 0 0000000 00000000 00000000 00000010
1 0 0000000 00000000 00000000 00000001
0 0 0000000 00000000 00000000 00000000

 

Zuweisungs- und Verbundoperatoren

Das Gleichzeichen = dient in Java als Zuweisungsoperator. Die Anweisung

x = y + z;

ist nicht als mathematische Gleichung zuverstehen, sondern als Zuweisung des Ausdrucks auf der echten Seite (y+z) auf die Variable x auf der linken Seite.

Zuweisungen wie:

x = y = 8;

sind auch möglich. Sie haben die gleiche Bedeutung wie

y = 8;
x = y;

Für die meisten binären Operatoren gibt es Verbundoperatoren mit denen man einer Variable etwas zuweisen kann und gleichzeitig den alten Wert verwenden kann:

Verbundoperator
Verbundoperator entspricht
a += b a = a + b
a -= b a = a - b
a *= b a = a * b
a /= b a = a / b
a %= b a = a % b
a &= b a = a & b
a |= b a = a | b
a ^= b a = a ^ b
a <<= b a = a << b
a >>= b a = a > b
a >>>= b a = a >>> b

 

Auswertungsreihenfolge

Für Ausdrücke mit mehreren Operatoren gelten die folgenden Regeln in Bezug auf die Reihenfolge der Auswertung:

  1. Teilausdrücke in runden Klammern werden wie in der Mathematik als erstes ausgewertet
  2. Ausdrücke mit unären Operatoren werden anschließend ausgewertet
  3. Zuletzt werden Teilausdrücke mit mehrstelligen Operatoren ausgewertet

Unäre Operatoren haben alle die gleiche Priorität

Ausführungsreihenfolge von Operatoren

Die Ausführungsreihenfolge von Operatoren bestimmt wie ein Term aufgelöst wir.

Tipp: Es ist guter Programmstil Terme übersichtlich zu gestalten. Verwenden Sie im Zweifelsfall Klammern!

Ausführungsreihenfolge von Operatoren
Rang Operator Beschreibung
1 =, +=, -=, *= ... Zuweisungsoperator
2 ?: Bedingungsoperator
3 || Logische Oder
4 && Logisches Und
5 | logisches oder bitweises Oder
6 ^ logisches oder bitweises Entweder-Oder
7 & logisches oder bitweises Und
8 ==, != Vergleichsoperatoren: Gleich, Ungleich
9 <, <=, >, >= Vergleichsoperatoren
10 <<, >>, >>> Schiebeoperatoren
11 +, - Addition, Subtraktion, Verketten von Zeichenketten
12 *, /, % Multiplikation, Division, Rest
13 ++, --, +, -, ~, ! unäre (einstellige) Operatoren

 Auswertung von Operatoren mit gleicher Priorität

Es kann vorkommen, dass ein Ausdruck mehrere Operatoren der gleichen Priorität besitzt. In diesen Fällen wird die Auswertereihenreihenfolge durch die Assoziativität der Operatoren bestimmt.

Definition
Operatorenasoziativität
Die Assoziativität von Operatoren ist die Reihenfolge in der Operanden durch Operatoren gleicher Priorität verknüpft werden

Ist ein Operator linksassoziativ, wird zuerst der linke Operand ausgewertet. Das Beispiel zeigt den Plus- und Minusoperator. Beide haben die gleiche Priorität. Hier wird zuerst der Operand a+b ausgewertet.

linksassoziative Operanden

Einige Operatoren in Java sind rechtsassoziativ. Ein Beispiel hierfür ist der Zuweisungsoperator

Bewertungsreihenfolge der Operanden eines Operators

Definition
Bewertungsreihenfolge der Operanden
In Java werden die Operanden eines Operators strikt von links nach rechts ausgewertet.

Diese Regel ist insbesondere wichtig, da Methoden und diverse Operatoren Nebeneffekte haben können. Das bedeutet, dass diese Operatoren den Wert von Variablen während der Auswertung des Gesamtausdrucks verändern. Beispiele sind die Inkrement- und Dekrementoperatoren.

j = i-- -i;

ist ein zulässiger Ausdruck in Java.  Der Wert der j zugewiesen wird ist immer 1;

Die Auswertung dieser Zuweisung geschieht in den folgenden Schritten:

  1. Auswertung des Subtrahenden (und Zwischenspeicherung)
  2. Dekrement von i
  3. Auswertung des Minuend und Berechnung der Differenz
  4. Zuweisung der Differenz auf j

Ein Beispielprogramm zum Testen:

package s1.block2.skript;
public class PrePostInkrement {
    public static void main(String[] args) {
        int i = 4;
        int j;
        
        j=i-- -i;
        System.out.println("i: " +i+", j= "+j);
    } 
}

Ausgabe:

i: 3, j= 1

Die Auswertung des Ausdrucks und der Zuweisung j= i-- -i; findet wie folgt statt:

i j j= i-- -i; Kommentar
4 0 j = 4 - i; Bestimmung des Minuend der Subtraktion
3 0 j = 4 - i; Postdekrement von i
3 0 j = 4 -3; Bestimmung des Subtrahend der Subtraktion
3 0 j = 1; Bestimmung der Differenz
3 1   Zuweisung

Regeln für den Ergebnistyp von arithmetischen Ausdrücken (Widening Conversions)

Java kann alle arithmetischen Operationen auch ausführen wenn die Zahlentypen im Ausdruck unterschiedlich sind. Das Ergebnis der Berechnung hängt von den Typen des Ausdrucks ab. Es gilt in der folgenden Reihenfolge:

  1. Ist einer der Typen ein double, so wird das Ergebnis zum Typ double konvertiert.
  2. Falls nicht, wird das Ergebnis zu einem float Typen konvertiert wenn ein Typ ein float Typ ist.
  3. Falls nicht, wird das Ergebnis zu einem long Typen konvertiert wenn ein Typ ein long Typ ist.
  4. Falls nicht, werden beide Operanden zuerst zu einem int Typen konvertiert.

 

Anonymous (not verified)

Sun, 12/16/2012 - 13:53

Sie schreiben, dass "x=y=8;" die gleiche Bedeutung hat wie "x=8; y=8;". Dabei wird doch x der Wert von y zugewiesen und nicht direkt die Zahl 8, oder? Also müsste "x=y=8;" äquivalent sein mit "y=8; x=y" (da ja die Ausdrücke von rechts nach links ausgewertet werden). Oder?

Sie haben sehr, sehr wahrscheinlich recht.

Man müsste sich zur finalen Klärung den generierten Bytecode anschauen oder im Debugger zwischen die beiden Zuweisungen kommen.

Der folgende Javacode ist ein starkes Indiz, dass Sie recht haben:

int x,y;
x = y = 8;
//(x = y) = 8; // So etwas geht nicht
x = (y = 8); // So etwas geht. Diese Klammer ist an dieser Stelle wahrscheinlich redundant. y wird hier garantiert vorher belegt.
x = (y = 8)+1; // So etwas geht auch. Damit wird das Prinzip auf die Spitze getrieben. x erhält jetzt den Wert 9.
System.out.println(x);
System.out.println(y);

Hane den Text nach Ihrem Vorschlag geändert.

Anonymous (not verified)

Wed, 01/16/2013 - 13:35

DHBW-Mannheim - Java Vorlesung - hier sind wir gerade oder ??
Wer guckt alles und findet den comment???

___________c$$$$$$$$$$$$$$$$$$$$$$$$$$h,
________c$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
____d$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
____$$$,d$$$$$$$$$$$$$$$$$$$$$$$$$hc`?$$$$
___$$$u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$h,?$$
___$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$b$$$
___$$$$$P$$?$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
___$$$$$$$`$$$$$$$$$$$$$$$$$$$$$$$$$d$$$$$$
____$$$$$$c ,nn,?$$$$$$$$$$$$$$$,,`$$$$$$$$
_____$$ MMMMM`$$$$$$$$$$$$F,MMMb`$$$$$$$$
______$$$MMTTM.?$$$$$$$$$$$,MMM $$$$$$$$
_______`$$$$$,M;;;`$$$$$$$$$$´M,,`,$$$$$$
__________?$$$$, ____________?$$$$,( ) $$$$$$$$$$ (´ ),$$$
____________`$$$$.`-´ $$$$$$$$$$,`--´,$$$´
____________$$$$$hh$$$$$????$$$hc$$$$$$$´
___________d$$$$$$$$$ `======´ $$$$$$$;
___________ $$$$$$$$$$$$c,,,,c$$$$$$$$$
____________?$$$$P $$$$$$?????$$??$$$$
______________________$$$$$
_____________________4$$$$$c
____________________,$$$$$$$
__________________z$ ________________> z$ _________________ ________________`$ _________________?L$$$$$$$$$$$:$
__________________?$$$$$$$$$$$d´
___________________`$$$$$$$$$$F
____________________`?$c`??3$F
____________________CCC_CCC
____________________,;CC_CC;;
____________________`CC__CCC
.,,,,,CCCCCCCCCCCCCCC__CCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCC__CCCCCCC,CCCCCCCCCCC
CCCCCCCCCCCCCCCCCC___CCCCC´`´CCCCCCCCCC

Anonymous (not verified)

Tue, 01/22/2013 - 16:39

public class PrePostInkrement {
public static void main(String[] args) {
int i = 4;
int j;

j=i-- -i;
System.out.println("i: " +i+", j= "+j);
}
}

Müsste hier für j nicht 0 rauskommen? Und i = 3?
Der Operator -- (also i--;) findet doch erst nach der Zuweisung statt oder?

Stefan Schneider

Tue, 01/22/2013 - 20:22

In reply to by Anonymous (not verified)

Ich habe den genauen Ablauf in das Skript eingebaut.
Das Dekrement findet statt nachdem der Minuend bestimmt worden ist.
Das bedeutet, das Dekrement findet nach der Zuweisung des Minuenden statt. Nicht nach der Zuweisung auf j!
Die Zuweisung des Minuenden kann man als Zuweisung auf eine temporäre Variable verstehen.

Anonymous (not verified)

Fri, 10/11/2019 - 11:24

Bei den unären arithmetischen Operatoren steht "Präidekrement" statt "Prädekrement".

Hallo,

der ternäre Operator ist ja rechtsassoziativ.

Weshalb ergibt der folgende Ausdruck dann " a größer b"?

int a = 10;
int b = 5;

String r = a > b ? "a größer b" : a < b ? "a kleiner b" : "beide gleich";
System.out.println( r );

Es müsste doch eigentlich erst a < b ausgewertet werden, oder?