2.3 Operatoren und Ausdrücke
2.3 Operatoren und AusdrückeAusdrü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:
|
Binäre Operatoren haben zwei Operanden. Beispiele sind:
|
Arithmetische Operatoren
Die arithmetischen Operatoren können auf die folgenden Typen angewendet werden
- byte
- short
- int
- long
- float
- double
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
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
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.
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.
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
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 |
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
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:
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
Die interne Darstellung der verwendeten Werte:
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 | 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:
- Teilausdrücke in runden Klammern werden wie in der Mathematik als erstes ausgewertet
- Ausdrücke mit unären Operatoren werden anschließend ausgewertet
- 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!
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.
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.
Einige Operatoren in Java sind rechtsassoziativ. Ein Beispiel hierfür ist der Zuweisungsoperator
Bewertungsreihenfolge der Operanden eines Operators
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:
- Auswertung des Subtrahenden (und Zwischenspeicherung)
- Dekrement von i
- Auswertung des Minuend und Berechnung der Differenz
- 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:
- Ist einer der Typen ein double, so wird das Ergebnis zum Typ double konvertiert.
- Falls nicht, wird das Ergebnis zu einem float Typen konvertiert wenn ein Typ ein float Typ ist.
- Falls nicht, wird das Ergebnis zu einem long Typen konvertiert wenn ein Typ ein long Typ ist.
- Falls nicht, werden beide Operanden zuerst zu einem int Typen konvertiert.
- 101845 views
Tippfehler
"ist x ist gleich y ?"
Korrekt.
Danke. Ich habe den Fehler korrigiert.
Mehrfachzuweisung
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?
Richtige Überlegung
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:
Hane den Text nach Ihrem Vorschlag geändert.
Hallo Kurs WIBI12C
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
Rechnung
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?
Erklärung
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.
Ausführungsreihenfolge von Operatoren
Laut diesem Unterpunkt ist Strich vor Punkt. Bitte erklären.
Tippfehler
Bei den unären arithmetischen Operatoren steht "Präidekrement" statt "Prädekrement".
Sehr gut beobachtet
Vielen Dank. Wurde verbessert.
Ternärer Operator rechtsassoziativ?
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?