Java Language
Operatoren
Suche…
Einführung
Operatoren in der Java-Programmiersprache sind spezielle Symbole, die bestimmte Operationen an einem, zwei oder drei Operanden ausführen und dann ein Ergebnis zurückgeben.
Bemerkungen
Ein Operator ist ein Symbol (oder Symbole), das ein Java-Programm anweist, eine Operation an einem, zwei oder drei Operanden auszuführen. Ein Operator und seine Operanden bilden einen Ausdruck (siehe Thema Ausdrücke). Die Operanden eines Operators sind selbst Ausdrücke.
In diesem Thema werden ungefähr 40 verschiedene Operatoren beschrieben, die von Java definiert werden. Das separate Thema "Ausdrücke" erläutert:
- wie Operatoren, Operanden und andere Dinge zu Ausdrücken kombiniert werden,
- wie die Ausdrücke bewertet werden und
- wie Ausdruckstypen, Konvertierungen und Ausdrucksauswertung funktionieren.
Der String-Verkettungsoperator (+)
Das +
-Symbol kann drei verschiedene Operatoren in Java bedeuten:
- Wenn vor dem
+
kein Operand vorhanden ist, ist dies der unäre Plus-Operator. - Wenn zwei Operanden vorhanden sind, sind beide numerisch. dann ist es der binäre Addition-Operator.
- Wenn zwei Operanden vorhanden sind und mindestens einer von ihnen ein
String
, handelt es sich um den binären Verkettungsoperator.
Im einfachen Fall verknüpft der Verkettungsoperator zwei Zeichenfolgen, um eine dritte Zeichenfolge zu erhalten. Zum Beispiel:
String s1 = "a String";
String s2 = "This is " + s1; // s2 contains "This is a String"
Wenn einer der beiden Operanden kein String ist, wird er wie folgt in einen String
konvertiert:
Ein Operand, dessen Typ ein primitiver Typ ist, wird wie durch Aufruf von
toString()
für den geschachtelten Wert konvertiert.Ein Operand, dessen Typ ein Referenztyp ist, wird durch Aufrufen der
toString()
Methode des Operanden konvertiert. Wenn der Operandnull
ist oder wenn dietoString()
Methodenull
zurückgibt, wird stattdessen das Zeichenfolgenliteral"null"
verwendet.
Zum Beispiel:
int one = 1;
String s3 = "One is " + one; // s3 contains "One is 1"
String s4 = null + " is null"; // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
// "{} is [I@xxxxxxxx"
Die Erklärung für das s5
Beispiel besteht darin, dass die toString()
-Methode für Array-Typen von java.lang.Object
geerbt wird und das Verhalten darin besteht, eine Zeichenfolge zu erzeugen, die aus dem Typnamen und dem Identitäts-Hashcode des Objekts besteht.
Der Verkettungsoperator wird angegeben, um ein neues String
Objekt zu erstellen, außer wenn der Ausdruck ein konstanter Ausdruck ist. Im letzteren Fall wird der Ausdruck beim Kompilierungstyp ausgewertet, und sein Laufzeitwert entspricht einem String-Literal. Dies bedeutet, dass beim Aufteilen eines langen String-Literal wie folgt kein Laufzeit-Overhead entsteht:
String typing = "The quick brown fox " +
"jumped over the " +
"lazy dog"; // constant expression
Optimierung und Effizienz
Mit Ausnahme von Konstantenausdrücken erstellt jeder Zeichenfolgenverkettungsausdruck ein neues String
Objekt. Betrachten Sie diesen Code:
public String stars(int count) {
String res = "";
for (int i = 0; i < count; i++) {
res = res + "*";
}
return res;
}
In der obigen Methode wird bei jeder Iteration der Schleife ein neuer String
, der um ein Zeichen länger ist als die vorherige Iteration. Jede Verkettung kopiert alle Zeichen in den Operanden - Strings die neuen bilden String
. stars(N)
werden also:
- Erstellen Sie
N
neueString
Objekte und werfen Sie alle außer dem letzten weg. - kopiere
N * (N + 1) / 2
Zeichen und - generiere
O(N^2)
Bytes Müll.
Dies ist für große N
sehr teuer. In der Tat kann jeder Code, der Zeichenfolgen in einer Schleife verkettet, dieses Problem haben. Ein besserer Weg, dies zu schreiben, wäre wie folgt:
public String stars(int count) {
// Create a string builder with capacity 'count'
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append("*");
}
return sb.toString();
}
Idealerweise sollten Sie die Kapazität des StringBuilder
festlegen. Wenn dies jedoch nicht praktikabel ist, vergrößert die Klasse automatisch das Sicherungsarray, das der Builder zum Speichern von Zeichen verwendet. (Hinweis: Die Implementierung erweitert das Hintergrundarray exponentiell. Diese Strategie hält die Menge an Zeichen, die auf O(N)
anstatt auf O(N^2)
kopiert wird.)
Einige Leute wenden dieses Muster auf alle String-Verkettungen an. Dies ist jedoch nicht erforderlich, da JLS es einem Java-Compiler ermöglicht, Zeichenfolgenverkettungen innerhalb eines einzelnen Ausdrucks zu optimieren. Zum Beispiel:
String s1 = ...;
String s2 = ...;
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";
wird normalerweise vom Bytecode-Compiler auf so etwas optimiert;
StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();
(Der JIT-Compiler kann dies weiter optimieren, wenn er davon ausgehen kann, dass s1
oder s2
nicht null
.) Beachten Sie jedoch, dass diese Optimierung nur innerhalb eines einzelnen Ausdrucks zulässig ist.
Kurz gesagt, wenn Sie über die Effizienz von String-Verkettungen besorgt sind:
- Optimieren Sie von Hand, wenn Sie wiederholte Verkettungen in einer Schleife (oder ähnlichem) durchführen.
- Optimieren Sie einen einzelnen Verkettungsausdruck nicht manuell.
Die arithmetischen Operatoren (+, -, *, /,%)
Die Java-Sprache stellt 7 Operatoren zur Verfügung, die Arithmetik für Ganzzahl- und Fließkommawerte ausführen.
- Es gibt zwei Operatoren
+
:- Der binäre Additionsoperator fügt eine Zahl zu einer anderen hinzu. (Es gibt auch einen binären
+
-Operator, der eine String-Verkettung ausführt. Dies wird in einem separaten Beispiel beschrieben.) - Der Operator unary plus tut nichts außer das Auslösen einer numerischen Promotion (siehe unten).
- Der binäre Additionsoperator fügt eine Zahl zu einer anderen hinzu. (Es gibt auch einen binären
- Es gibt zwei
-
Operatoren:- Der Operator für binäre Subtraktion subtrahiert eine Zahl von einer anderen.
- Der unäre Minusoperator entspricht dem Abzug seines Operanden von Null.
- Der binäre Multiplikationsoperator (*) multipliziert eine Zahl mit einer anderen.
- Der Binärdivisionsoperator (/) teilt eine Zahl durch eine andere.
- Der Operator für binäre Rest 1 (%) berechnet den Rest, wenn eine Zahl durch eine andere geteilt wird.
1. Dies wird oft fälschlicherweise als "Modulus" -Operator bezeichnet. "Rest" ist der Begriff, der von der JLS verwendet wird. "Modul" und "Rest" sind nicht dasselbe.
Operanden- und Ergebnistypen sowie numerische Promotion
Die Operatoren benötigen numerische Operanden und erzeugen numerische Ergebnisse. Bei den Operandentypen kann es sich um einen beliebigen primitiven numerischen Typ handeln (dh byte
, short
, char
, int
, long
, float
oder double
) oder um einen beliebigen numerischen Wrapper-Typ, der in java.lang
definiert ist. dh ( Byte
, Character
, Short
, Integer
, Long
, Float
oder Double
.
Der Ergebnistyp wird basierend auf den Typen des Operanden oder der Operanden wie folgt bestimmt:
- Wenn einer der Operanden
double
oderDouble
, ist der Ergebnistypdouble
. - Wenn einer der Operanden
float
oderFloat
, lautet der Ergebnistypfloat
. - Andernfalls, wenn einer der Operanden
long
oderLong
, ist der Ergebnistyplong
. - Ansonsten ist der Ergebnistyp
int
. Dies umfasstbyte
,short
undchar
Operanden sowie `int.
Der Ergebnistyp der Operation bestimmt, wie die arithmetische Operation ausgeführt wird und wie die Operanden behandelt werden
- Wenn der Ergebnistyp
double
, werden die Operanden aufdouble
erhöht, und die Operation wird unter Verwendung einer 64-Bit-IEE 754-Gleitkomma-Arithmetik ausgeführt. - Wenn der Ergebnistyp "
float
, werden die Operanden zum "float
, und die Operation wird unter Verwendung einer 32-Bit-Gleitkomma-Arithmetik (IEE 754 mit einfacher Genauigkeit) ausgeführt. - Wenn der Ergebnistyp
long
, werden die Operanden zulong
heraufgestuft, und die Operation wird mit einer 64-Bit-Zweierkomplement-Binär-Ganzzahl-Arithmetik mit Vorzeichen ausgeführt. - Wenn der Ergebnistyp "
int
, werden die Operanden zu "int
, und die Operation wird unter Verwendung einer 32-Bit-Zweierkomplement-Binär-Ganzzahl-Arithmetik mit Vorzeichen ausgeführt.
Die Promotion erfolgt in zwei Schritten:
- Wenn es sich bei dem Operandentyp um einen Wrapper-Typ handelt, wird der Operandenwert nicht mit einem Wert des entsprechenden primitiven Typs gefüllt .
- Bei Bedarf wird der Primitivtyp auf den erforderlichen Typ hochgestuft:
- Die Förderung von ganzen Zahlen zu
int
oderlong
ist verlustfrei. - Die Beförderung des
float
zumdouble
ist verlustfrei. - Die Aufwertung einer Ganzzahl auf einen Gleitkommawert kann zu Genauigkeitsverlusten führen. Die Konvertierung wird unter Verwendung der Semantik "Round-to-next" von IEE 768 durchgeführt.
- Die Förderung von ganzen Zahlen zu
Die Bedeutung der Spaltung
Der Operator / teilt den linken Operanden n
(den Dividend ) und den rechten Operanden d
(den Divisor ) und erzeugt das Ergebnis q
(den Quotienten ).
Java Integer Division rundet gegen Null. Der JLS-Abschnitt 15.17.2 legt das Verhalten der Java-Ganzzahldivision wie folgt fest:
Der für die Operanden
n
undd
erzeugte Quotient ist ein ganzzahliger Wertq
dessen Größe so groß wie möglich ist, während|d ⋅ q| ≤ |n|
erfüllt wird|d ⋅ q| ≤ |n|
. Außerdem istq
positiv, wenn|n| ≥ |d|
undn
undd
haben dasselbe Vorzeichen, aberq
ist negativ, wenn|n| ≥ |d|
undn
undd
haben entgegengesetzte Vorzeichen.
Es gibt einige Sonderfälle:
- Wenn
n
MIN_VALUE
ist und der Divisor -1 ist, tritt ein Ganzzahlüberlauf auf und das Ergebnis istMIN_VALUE
. In diesem Fall wird keine Ausnahme ausgelöst. - Wenn
d
0 ist, wird `ArithmeticException ausgelöst.
Bei der Java-Gleitkommadivision müssen mehr Randfälle berücksichtigt werden. Die Grundidee ist jedoch, dass das Ergebnis q
der Wert ist, der am ehesten erfüllt ist, um d . q = n
zu erfüllen d . q = n
.
Gleitkommadivision führt niemals zu einer Ausnahme. Stattdessen führen Operationen, die durch Null dividieren, zu INF- und NaN-Werten. siehe unten.
Die Bedeutung von Rest
Im Gegensatz zu C und C ++ arbeitet der Restoperator in Java sowohl mit Ganzzahl- als auch mit Gleitkommaoperationen.
Für ganzzahlige Fälle ist das Ergebnis von a % b
als Zahl r
definiert, so dass (a / b) * b + r
gleich a
, wobei /
, *
und +
die geeigneten Java-Ganzzahloperatoren sind. Dies gilt in allen Fällen, außer wenn b
Null ist. In diesem Fall führt der Rest zu einer ArithmeticException
.
Aus der obigen Definition folgt, dass a % b
nur dann negativ sein kann, wenn a
negativ ist, und es ist nur positiv, wenn a
positiv ist. Außerdem ist die Größe von a % b
immer kleiner als die Größe von b
.
Die Floating-Point-Restoperation ist eine Verallgemeinerung des Ganzzahlfalls. Das Ergebnis von a % b
ist der Rest r
, der durch die mathematische Beziehung r = a - (b ⋅ q)
wobei:
-
q
ist eine ganze Zahl, - es ist nur negativ, wenn
a / b
negativ ist, positiv nur, wenna / b
positiv ist, und - seine Größe ist so groß wie möglich, ohne die Größe des wahren mathematischen Quotienten von
a
undb
zu überschreiten.
Gleitpunktrest kann INF
und NaN
Werte in NaN
erzeugen, beispielsweise wenn b
Null ist; siehe unten. Es wird keine Ausnahme ausgelöst.
Wichtige Notiz:
Das von
%
berechnete Ergebnis einer Gleitkomma-Math.IEEEremainder
ist nicht dasselbe wie das Ergebnis, das von der durch IEEE 754 definiertenMath.IEEEremainder
erzeugt wird. Der Rest der IEEE 754 kann mit der BibliotheksmethodeMath.IEEEremainder
berechnet werden.
Ganzzahlüberlauf
Java-Ganzzahlwerte für 32 und 64 Bit sind vorzeichenbehaftet und verwenden eine binäre Darstellung mit zwei Komplementen. Beispielsweise kann der Zahlenbereich als (32 Bit) int
-2 31 bis +2 31 - 1 dargestellt werden.
Wenn Sie zwei N-Bit-Integer (N = 32 oder 64) addieren, subtrahieren oder mehrere N-Bits addieren, ist das Ergebnis der Operation möglicherweise zu groß, um als N-Bit-Integer dargestellt zu werden. In diesem Fall führt die Operation zu einem Ganzzahlüberlauf , und das Ergebnis kann wie folgt berechnet werden:
- Die mathematische Operation wird ausgeführt, um eine Zwillingskomplementdarstellung der gesamten Zahl zu erhalten. Diese Darstellung wird größer als N Bits sein.
- Die unteren 32 oder 64 Bits der Zwischendarstellung werden als Ergebnis verwendet.
Es ist zu beachten, dass der Integer-Überlauf unter keinen Umständen zu Ausnahmen führt.
Gleitkomma-INF- und NAN-Werte
Java verwendet IEE 754-Gleitkommadaten für float
und double
. Diese Darstellungen haben einige spezielle Werte für die Darstellung von Werten, die außerhalb der Domäne der reellen Zahlen liegen:
- Die Werte "unendlich" oder "INF" geben zu große Zahlen an. Der
+INF
Wert gibt Zahlen an, die zu groß und positiv sind. Der-INF
Wert kennzeichnet zu große und negative Zahlen. - "Unbestimmt" / "keine Zahl" oder NaN bezeichnen Werte, die aus bedeutungslosen Operationen resultieren.
Die INF-Werte werden durch Floating-Operationen erzeugt, die einen Überlauf verursachen, oder durch Division durch Null.
Die NaN-Werte werden erzeugt, indem Null durch Null dividiert oder Null berechnet wird.
Überraschenderweise ist es möglich, Arithmetik mit INF- und NaN-Operanden auszuführen, ohne Ausnahmen auszulösen. Zum Beispiel:
- Addiert man + INF und einen endlichen Wert, erhält man + INF.
- Das Hinzufügen von + INF und + INF ergibt + INF.
- Addieren von + INF und -INF ergibt NaN.
- Division durch INF ergibt entweder +0.0 oder -0.0.
- Alle Operationen mit einem oder mehreren NaN-Operanden ergeben NaN.
Ausführliche Informationen finden Sie in den entsprechenden Unterabschnitten von JLS 15 . Beachten Sie, dass dies weitgehend "akademisch" ist. Bei typischen Berechnungen bedeutet ein INF
oder NaN
, dass etwas schiefgegangen ist. Sie haben zB unvollständige oder falsche Eingabedaten oder die Berechnung wurde falsch programmiert.
Die Gleichheitsoperatoren (==,! =)
Die Operatoren ==
und !=
Sind binäre Operatoren, die abhängig davon, ob die Operanden gleich sind, als true
oder false
ausgewertet werden. Der Operator ==
gibt true
wenn die Operanden gleich sind, andernfalls false
. Der Operator !=
Gibt false
wenn die Operanden gleich und andernfalls true
sind.
Diese Operatoren können mit primitiven Typen und Referenztypen verwendet werden, das Verhalten unterscheidet sich jedoch erheblich. Laut JLS gibt es drei verschiedene Gruppen dieser Operatoren:
- Die booleschen Operatoren
==
und!=
. - Die numerischen Operatoren
==
und!=
. - Die Referenzoperatoren
==
und!=
.
In allen Fällen ist der Ergebnistyp der Operatoren ==
und !=
Jedoch boolean
.
Die numerischen Operatoren ==
und !=
Wenn einer (oder beide) der Operanden eines Operators ==
oder !=
Ein primitiver numerischer Typ ist ( byte
, short
, char
, int,
long
int,
, float
oder double
), handelt es sich bei dem Operator um einen Zahlenvergleich. Der zweite Operand muss entweder ein numerischer Grundtyp oder ein numerischer Typ mit Rahmen sein.
Das Verhalten anderer numerischer Operatoren lautet wie folgt:
- Wenn es sich bei einem der Operanden um einen Box-Typ handelt, ist er nicht im Boxmodus.
- Wenn einer der Operanden jetzt ein
byte
, einshort
oder einchar
, wird er zu einemint
. - Wenn die Typen der Operanden nicht gleich sind, wird der Operand mit dem Typ "Kleiner" zum Typ "Größer" befördert.
- Der Vergleich wird dann wie folgt durchgeführt:
- Wenn die heraufgestuften Operanden
int
oderlong
die Werte getestet, um zu sehen, ob sie identisch sind. - Wenn die beförderten Operanden
float
oderdouble
sind, giltfloat
:- Die zwei Versionen von Null (
+0.0
und-0.0
) werden als gleich behandelt - Ein
NaN
Wert wird als nicht gleichwertig behandelt und - Andere Werte sind gleich, wenn ihre IEEE 754-Darstellungen identisch sind.
- Die zwei Versionen von Null (
- Wenn die heraufgestuften Operanden
Hinweis: Sie müssen vorsichtig sein, wenn Sie ==
und !=
Verwenden, um Fließkommawerte zu vergleichen.
Die booleschen Operatoren ==
und !=
Wenn beide Operanden boolean
sind oder einer boolean
und der andere Boolean
, sind diese Operatoren die Booleschen Operatoren ==
und !=
. Das Verhalten ist wie folgt:
- Wenn einer der Operanden ein
Boolean
, ist er nicht in der Box. - Die ungepackten Operanden werden getestet und das boolesche Ergebnis wird gemäß der folgenden Wahrheitstabelle berechnet
EIN | B | A == B | A! = B |
---|---|---|---|
falsch | falsch | wahr | falsch |
falsch | wahr | falsch | wahr |
wahr | falsch | falsch | wahr |
wahr | wahr | wahr | falsch |
Es gibt zwei "Fallstricke", die es ratsam machen, ==
und !=
Sparsam mit den Wahrheitswerten zu verwenden:
Wenn Sie mit
==
oder!=
ZweiBoolean
Objekte vergleichen, werden die Referenzoperatoren verwendet. Dies kann zu einem unerwarteten Ergebnis führen. Siehe Pitfall: Verwenden Sie ==, um primitive Wrapper-Objekte wie Integer zu vergleichenDer Operator
==
kann leicht als=
eingegeben werden. Bei den meisten Operandentypen führt dieser Fehler zu einem Kompilierungsfehler. Beiboolean
undBoolean
Operanden führt der Fehler jedoch zu falschem Laufzeitverhalten. siehe Pitfall - Mit '==' einen boolean testen
Die Referenzoperatoren ==
und !=
Wenn beide Operanden Objektreferenzen sind, prüfen die Operatoren ==
und !=
Ob die beiden Operanden auf dasselbe Objekt verweisen . Das ist oft nicht das, was Sie wollen. Um zu testen, ob zwei Objekte nach Wert gleich sind , sollte stattdessen die Methode .equals()
verwendet werden.
String s1 = "We are equal";
String s2 = new String("We are equal");
s1.equals(s2); // true
// WARNING - don't use == or != with String values
s1 == s2; // false
Warnung: Die Verwendung von ==
und !=
Zum Vergleichen von String
Werten ist in den meisten Fällen falsch . Siehe http://www.riptutorial.com/java/example/16290/pitfall-- using ---- to- compare-strings . Ein ähnliches Problem gilt für primitive Wrapper-Typen. Siehe http://www.riptutorial.com/java/example/8996/pitfall-- using ---- to- compare- primitive- wrappers- objects- such- as- integer .
Über die NaN-Randfälle
In JLS 15.21.1 heißt es:
Wenn einer der Operanden
NaN
, ist das Ergebnis von==
false
aber das Ergebnis von!=
Isttrue
. Tatsächlich ist der Testx != x
true
danntrue
wenn der Wert vonx
NaN
.
Dieses Verhalten ist (für die meisten Programmierer) unerwartet. Wenn Sie testen, ob ein NaN
Wert sich selbst entspricht, lautet die Antwort "Nein, ist es nicht!". Mit anderen Worten: ==
ist für NaN
Werte nicht reflexiv .
Dies ist jedoch keine Java-"Kuriosität", dieses Verhalten ist in den IEEE 754-Fließkomma-Standards angegeben, und Sie werden feststellen, dass es von den meisten modernen Programmiersprachen implementiert wird. (Weitere Informationen finden Sie unter http://stackoverflow.com/a/1573715/139985 ... Sie stellen fest, dass dies von jemandem geschrieben wurde, der "im Raum war, als die Entscheidungen getroffen wurden"!
Die Inkrement- / Dekrement-Operatoren (++ / -)
Variablen können mit den Operatoren ++
und --
um 1 erhöht oder dekrementiert werden.
Wenn die Operatoren ++
und --
auf Variablen folgen, werden sie als Nachinkrement bzw. Nach-Dekrement bezeichnet.
int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again
Wenn die Operatoren ++
und --
vor den Variablen stehen, werden die Operationen als Vorinkrement bzw. Vor-Dekrement bezeichnet.
int x = 10;
--x; // x now equals 9
++x; // x now equals 10
Wenn der Operator der Variablen vorangeht, ist der Wert des Ausdrucks der Wert der Variablen, nachdem sie inkrementiert oder dekrementiert wurde. Wenn der Operator der Variablen folgt, ist der Wert des Ausdrucks der Wert der Variablen, bevor sie erhöht oder dekrementiert wird.
int x=10;
System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10
Achten Sie darauf, keine Nachinkremente oder Dekremente zu überschreiben. Dies geschieht, wenn Sie am Ende eines Ausdrucks einen Post-In / Decrement-Operator verwenden, der der In / Decrement-Variablen selbst neu zugewiesen wird. Das Ein- / Dekrement hat keine Auswirkungen. Obwohl die Variable auf der linken Seite korrekt inkrementiert wird, wird ihr Wert sofort mit dem zuvor ausgewerteten Ergebnis von der rechten Seite des Ausdrucks überschrieben:
int x = 0;
x = x++ + 1 + x++; // x = 0 + 1 + 1
// do not do this - the last increment has no effect (bug!)
System.out.println(x); // prints 2 (not 3!)
Richtig:
int x = 0;
x = x++ + 1 + x; // evaluates to x = 0 + 1 + 1
x++; // adds 1
System.out.println(x); // prints 3
Der bedingte Operator (? :)
Syntax
{zu bewertende Bedingung} ? {Anweisung-ausgeführt auf-wahr} : {Anweisung-ausgeführt auf-falsch}
Wie in der Syntax gezeigt, verwendet der Bedingungsoperator (auch als der ternäre Operator 1 bezeichnet ) den ?
(Fragezeichen) und :
(Doppelpunkt) Zeichen, um einen bedingten Ausdruck von zwei möglichen Ergebnissen zu ermöglichen. Es kann verwendet werden, um längere if-else
Blöcke zu ersetzen, um je nach Bedingung einen von zwei Werten zurückzugeben.
result = testCondition ? value1 : value2
Ist äquivalent zu
if (testCondition) {
result = value1;
} else {
result = value2;
}
Es kann gelesen werden als : Wenn testCondition wahr ist, setze das Ergebnis auf value1; Andernfalls setzen Sie das Ergebnis auf value2 ”.
Zum Beispiel:
// get absolute value using conditional operator
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"
Ist äquivalent zu
// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
absValue = -a;
} else {
absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"
Gemeinsame Nutzung
Sie können den bedingten Operator für bedingte Zuweisungen verwenden (z. B. Nullprüfung).
String x = y != null ? y.toString() : ""; //where y is an object
Dieses Beispiel entspricht:
String x = "";
if (y != null) {
x = y.toString();
}
Da der Bedingungsoperator über den Zuweisungsoperatoren die zweitniedrigste Priorität hat, ist es selten erforderlich, eine Klammer um die Bedingung zu verwenden. In Kombination mit anderen Operatoren ist jedoch eine Klammer um das gesamte Konstrukt des Bedingten Operators erforderlich:
// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7
// parenthesis required
7 * (a > 0 ? 2 : 5)
Bedingte Operatoren können auch im dritten Teil verschachtelt werden, wobei sie eher wie Verketten oder wie eine switch-Anweisung funktionieren.
a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
"a, b, and c are false"
//Operator precedence can be illustrated with parenthesis:
a ? x : (b ? y : (c ? z : w))
Fußnote:
1 - Sowohl die Java-Sprachspezifikation als auch das Java-Lernprogramm rufen den Operator ( ? :
:) Als Bedingungsoperator auf . Das Tutorial sagt, dass es "auch als der ternäre Operator bekannt ist", da es (derzeit) der einzige von Java definierte ternäre Operator ist. Die Terminologie "Bedingter Operator" stimmt mit C und C ++ und anderen Sprachen mit einem äquivalenten Operator überein.
Die bitweisen und logischen Operatoren (~, &, |, ^)
Die Java-Sprache stellt 4 Operatoren bereit, die bitweise oder logische Operationen an ganzzahligen oder booleschen Operanden ausführen.
- Der Complement-Operator (
~
) ist ein unärer Operator, der eine bitweise oder logische Invertierung der Bits eines Operanden durchführt. siehe JLS 15.15.5. . - Der Operator AND (
&
) ist ein binärer Operator, der ein bitweises oder logisches "und" von zwei Operanden ausführt. siehe JLS 15.22.2. . - Der Operator OR (
|
) ist ein binärer Operator, der ein bitweises oder logisches "Inclusive or" von zwei Operanden ausführt. siehe JLS 15.22.2. . - Der XOR (
^
) - Operator ist ein binärer Operator, der ein bitweises oder logisches "Exklusiv-Oder" von zwei Operanden ausführt. siehe JLS 15.22.2. .
Die logischen Operationen, die von diesen Operatoren ausgeführt werden, wenn die Operanden Boolesche Werte sind, können wie folgt zusammengefasst werden:
EIN | B | ~ A | A & B | A | B | A ^ B |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
Beachten Sie, dass für Integer-Operanden die obige Tabelle beschreibt, was für einzelne Bits geschieht. Die Operatoren bearbeiten tatsächlich alle 32 oder 64 Bits des Operanden oder der Operanden parallel.
Operandentypen und Ergebnistypen.
Die üblichen arithmetischen Konvertierungen gelten, wenn die Operanden Ganzzahlen sind. Häufige Anwendungsfälle für die bitweisen Operatoren
Der Operator ~
wird verwendet, um einen booleschen Wert umzukehren oder alle Bits in einem Ganzzahloperanden zu ändern.
Der Operator &
dient zum "Ausblenden" einiger Bits in einem Ganzzahloperanden. Zum Beispiel:
int word = 0b00101010;
int mask = 0b00000011; // Mask for masking out all but the bottom
// two bits of a word
int lowBits = word & mask; // -> 0b00000010
int highBits = word & ~mask; // -> 0b00101000
Die |
Operator wird verwendet, um die Wahrheitswerte von zwei Operanden zu kombinieren. Zum Beispiel:
int word2 = 0b01011111;
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask); // -> 0b01011110
Der ^
Operator wird zum Umschalten oder "Umdrehen" von Bits verwendet:
int word3 = 0b00101010;
int word4 = word3 ^ mask; // -> 0b00101001
Weitere Beispiele für die Verwendung der bitweisen Operatoren finden Sie unter Bitmanipulation
Die Instanz des Operators
Dieser Operator prüft, ob das Objekt von einem bestimmten Klassen- / Schnittstellentyp ist. Instanz des Operators lautet:
( Object reference variable ) instanceof (class/interface type)
Beispiel:
public class Test {
public static void main(String args[]){
String name = "Buyya";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
Dies würde folgendes Ergebnis ergeben:
true
Dieser Operator gibt immer noch true zurück, wenn das zu vergleichende Objekt mit dem Typ rechts kompatibel ist.
Beispiel:
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
Dies würde folgendes Ergebnis ergeben:
true
Die Zuweisungsoperatoren (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = und ^ =)
Der linke Operand für diese Operatoren muss entweder eine nicht endgültige Variable oder ein Element eines Arrays sein. Der Operand für die rechte Hand muss mit dem linken Operanden kompatibel sein. Dies bedeutet, dass entweder die Typen gleich sein müssen oder der Typ des rechten Operanden durch Kombination von Boxing, Unboxing oder Expanding in den Typ des linken Operandentyps konvertierbar sein muss. (Für vollständige Details siehe JLS 5.2 .)
Die genaue Bedeutung der Operatoren "Operation and Assign" wird in JLS 15.26.2 wie folgt angegeben:
Ein zusammengesetzter Zuordnungsausdruck der Form
E1 op= E2
ist äquivalent zuE1 = (T) ((E1) op (E2))
, wobeiT
der Typ vonE1
, außer dassE1
nur einmal ausgewertet wird.
Beachten Sie, dass vor der endgültigen Zuweisung eine implizite Typumwandlung vorliegt.
1. =
Der einfache Zuweisungsoperator: weist dem linken Operanden den Wert des rechten Operanden zu.
Beispiel:
c = a + b
addiert den Wert vona + b
zum Wert vonc
und weist ihnc
2. +=
Der Operator "Hinzufügen und Zuweisen": fügt den Wert des Operanden für die linke Hand zum Wert des Operanden für die linke Hand hinzu und weist das Ergebnis dem linken Operanden zu. Wenn der linke Operand den Typ String
, handelt es sich um einen Operator "Verketten und Zuweisen".
Beispiel:
c += a
ungefährc = c + a
3. -=
Der Operator "subtrahieren und zuordnen": subtrahiert den Wert des rechten Operanden vom Wert des linken Operanden und weist das Ergebnis dem linken Operanden zu.
Beispiel:
c -= a
ungefährc = c - a
4. *=
Der Operator "Multiplizieren und Zuweisen": multipliziert den Wert des Operanden für die rechte Hand mit dem Wert des Operanden für die linke Hand und weist das Ergebnis dem linken Operanden zu. .
Beispiel:
c *= a
ungefährc = c * a
5. /=
Der Operator "Teilen und Zuweisen": Dividiert den Wert des Operanden für die rechte Hand durch den Wert des Operanden für die linke Hand und weist das Ergebnis dem linken Operanden zu.
Beispiel:
c /*= a
ungefährc = c / a
6. %=
Der Operator "Modulus und Zuweisung": Berechnet den Modul des Werts des Operanden für die rechte Hand anhand des Werts des Operanden für die linke Hand und weist das Ergebnis dem linken Operanden zu.
Beispiel:
c %*= a
ungefährc = c % a
7. <<=
Der Operator "Links verschieben und zuweisen".
Beispiel:
c <<= 2
ungefährc = c << 2
8. >>=
Der Operator "Arithmetik rechts verschieben und zuweisen".
Beispiel:
c >>= 2
ungefährc = c >> 2
9. >>>=
Der Operator "logisch rechts verschieben und zuweisen".
Beispiel:
c >>>= 2
ungefährc = c >>> 2
10. &=
Der Operator "bitweise und und zuweisen".
Beispiel:
c &= 2
ungefährc = c & 2
11. |=
Der Operator "bitweise oder und zuweisen".
Beispiel:
c |= 2
ungefährc = c | 2
12. ^=
Der Operator "bitweises Exklusiv- oder Zuweisen".
Beispiel:
c ^= 2
ungefährc = c ^ 2
Die Bedingungs- und Bedingungsoperatoren (&& und ||)
Java bietet einen Bedingungs- und einen Bedingungs-Operator, die beide einen oder zwei Operanden vom Typ boolean
annehmen und ein boolean
Ergebnis erzeugen. Diese sind:
&&
- der bedingte AND-Operator||
- die bedingten ODER-Operatoren. Die Auswertung von<left-expr> && <right-expr>
entspricht dem folgenden Pseudocode:{ boolean L = evaluate(<left-expr>); if (L) { return evaluate(<right-expr>); } else { // short-circuit the evaluation of the 2nd operand expression return false; } }
Die Bewertung von <left-expr> || <right-expr>
entspricht dem folgenden Pseudocode:
{
boolean L = evaluate(<left-expr>);
if (!L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return true;
}
}
Wie der obige Pseudocode zeigt, entspricht das Verhalten der Kurzschlussoperatoren der Verwendung von if
/ else
Anweisungen.
Beispiel - Verwenden von && als Guard in einem Ausdruck
Das folgende Beispiel zeigt das am häufigsten verwendete Verwendungsmuster für den Operator &&
. Vergleichen Sie diese beiden Versionen einer Methode, um zu testen, ob eine bereitgestellte Integer
Null ist.
public boolean isZero(Integer value) {
return value == 0;
}
public boolean isZero(Integer value) {
return value != null && value == 0;
}
Die erste Version funktioniert in den meisten Fällen, aber wenn das value
Argument null
, wird eine NullPointerException
ausgelöst.
In der zweiten Version haben wir einen "Guard" -Test hinzugefügt. Der value != null && value == 0
wird ausgewertet, indem zuerst der value != null
getestet wird. Wenn der null
erfolgreich ist (dh als true
bewertet wird), wird der value == 0
ausgewertet. Wenn die null
- Test fehlschlägt, dann die Auswertung der value == 0
wird übersprungen (kurzgeschlossen), und wir haben keine bekommen NullPointerException
.
Beispiel - Verwendung von &&, um eine kostspielige Berechnung zu vermeiden
Das folgende Beispiel zeigt, wie &&
verwendet werden kann, um eine relativ kostenintensive Berechnung zu vermeiden:
public boolean verify(int value, boolean needPrime) {
return !needPrime | isPrime(value);
}
public boolean verify(int value, boolean needPrime) {
return !needPrime || isPrime(value);
}
In der ersten Version sind beide Operanden von |
wird immer ausgewertet, daher wird die (teure) isPrime
Methode unnötig aufgerufen. Die zweite Version vermeidet den unnötigen Aufruf mit ||
anstelle von |
.
Die Schichtoperatoren (<<, >> und >>>)
Die Java-Sprache bietet drei Operatoren für die bitweise Verschiebung von 32- und 64-Bit-Ganzzahlwerten. Dies sind alles binäre Operatoren, wobei der erste Operand der Wert ist, der verschoben werden soll, und der zweite Operand, wie weit verschoben werden soll.
Der
<<
oder Linksverschiebungsoperator verschiebt den durch den ersten Operanden gegebenen Wert um die Anzahl der durch den zweiten Operanden gegebenen Bitpositionen nach links . Die leeren Stellen am rechten Ende sind mit Nullen gefüllt.Der Operator ">>" oder arithmetische Verschiebung verschiebt den durch den ersten Operanden angegebenen Wert um die durch den zweiten Operanden angegebene Anzahl von Bitpositionen nach rechts . Die leeren Stellen am linken Ende werden durch Kopieren des am weitesten links befindlichen Bits gefüllt. Dieser Vorgang wird als Zeichenerweiterung bezeichnet .
Der Operator ">>>" oder der logische Rechtsverschiebung verschiebt den durch den ersten Operanden angegebenen Wert um die durch den zweiten Operanden angegebene Anzahl von Bitpositionen nach rechts . Die leeren Stellen am linken Ende sind mit Nullen gefüllt.
Anmerkungen:
Diese Operatoren erfordern als ersten Operanden einen
int
oderlong
Wert und erzeugen einen Wert mit demselben Typ wie der erste Operand. (Sie müssen eine explizite Typumwandlung verwenden, wenn Sie das Ergebnis einer Verschiebung einerbyte
,short
oderchar
Variablen zuweisen.)Wenn Sie einen Shift-Operator mit einem ersten Operanden verwenden, der ein
byte
, einchar
oder einshort
, wird er zu einemint
und der Vorgang erzeugt einint
.)Der zweite Operand wird modulo um die Anzahl der Bits der Operation reduziert, um den Betrag der Verschiebung anzugeben. Weitere Informationen zum mathematischen Konzept des Mods finden Sie unter Modul-Beispiele .
Die Bits, die durch die Operation nach links oder rechts verschoben werden, werden verworfen. (Java bietet keinen primitiven "Drehen" -Operator.)
Der arithmetische Verschiebungsoperator ist äquivalent, indem eine Zahl (Zweierkomplement) durch eine Potenz von 2 dividiert wird.
Der linke Verschiebungsoperator multipliziert eine Zahl (Zweierkomplement) mit einer Potenz von 2.
Die folgende Tabelle zeigt die Auswirkungen der drei Schichtbedienungen. (Die Zahlen wurden in binärer Schreibweise angegeben, um die Visualisierung zu erleichtern.)
Operand1 | Operand2 | << | >> | >>> |
---|---|---|---|---|
0b0000000000001011 | 0 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
0b0000000000001011 | 1 | 0b0000000000010110 | 0b0000000000000101 | 0b0000000000000101 |
0b0000000000001011 | 2 | 0b0000000000101100 | 0b0000000000000010 | 0b0000000000000010 |
0b0000000000001011 | 28 | 0b1011000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 31 | 0b1000000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 32 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
... | ... | ... | ... | ... |
0b1000000000001011 | 0 | 0b1000000000001011 | 0b1000000000001011 | 0b1000000000001011 |
0b1000000000001011 | 1 | 0b0000000000010110 | 0b1100000000000101 | 0b0100000000000101 |
0b1000000000001011 | 2 | 0b0000000000101100 | 0b1110000000000010 | 0b00100000000000100 |
0b1000000000001011 | 31 | 0b1000000000000000 | 0b1111111111111111 | 0b0000000000000001 |
Es gibt Beispiele für den Benutzer von Schichtoperatoren bei der Bit-Bearbeitung
Der Lambda-Operator (->)
Ab Java 8 wird der Operator Lambda ( ->
) verwendet, um einen Lambda-Ausdruck einzuführen. Es gibt zwei gängige Syntaxtypen, wie in diesen Beispielen veranschaulicht:
a -> a + 1 // a lambda that adds one to its argument
a -> { return a + 1; } // an equivalent lambda using a block.
Ein Lambda-Ausdruck definiert eine anonyme Funktion oder richtiger eine Instanz einer anonymen Klasse, die eine funktionale Schnittstelle implementiert.
(Dieses Beispiel ist hier der Vollständigkeit halber enthalten. Die vollständige Behandlung finden Sie im Thema Lambda-Ausdrücke .)
Die relationalen Operatoren (<, <=,>,> =)
Die Operatoren <
, <=
, >
und >=
sind binäre Operatoren zum Vergleichen numerischer Typen. Die Bedeutung der Operatoren ist wie erwartet. Wenn zum Beispiel a
und b
als byte
, short
, char
, int
, long
, float
, double
oder die entsprechenden Boxed-Typen deklariert sind:
- `a < b` tests if the value of `a` is less than the value of `b`.
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`.
- `a > b` tests if the value of `a` is greater than the value of `b`.
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`.
Der Ergebnistyp für diese Operatoren ist in allen Fällen boolean
.
Mit Vergleichsoperatoren können Zahlen mit unterschiedlichen Typen verglichen werden. Zum Beispiel:
int i = 1;
long l = 2;
if (i < l) {
System.out.println("i is smaller");
}
Beziehungsoperatoren können verwendet werden, wenn eine oder beide Zahlen Instanzen von geschachtelten numerischen Typen sind. Zum Beispiel:
Integer i = 1; // 1 is autoboxed to an Integer
Integer j = 2; // 2 is autoboxed to an Integer
if (i < j) {
System.out.println("i is smaller");
}
Das genaue Verhalten wird wie folgt zusammengefasst:
- Wenn es sich bei einem der Operanden um einen Box-Typ handelt, ist er nicht im Boxmodus.
- Wenn einer der Operanden jetzt ein
byte
, einshort
oder einchar
, wird er zu einemint
. - Wenn die Typen der Operanden nicht gleich sind, wird der Operand mit dem Typ "Kleiner" zum Typ "Größer" befördert.
- Der Vergleich wird mit den resultierenden Werten
int
,long
,float
oderdouble
.
Bei relationalen Vergleichen mit Fließkommazahlen ist Vorsicht geboten:
- Ausdrücke, die Fließkommazahlen berechnen, führen häufig zu Rundungsfehlern, da die Fließkommadaten des Computers eine begrenzte Genauigkeit aufweisen.
- Beim Vergleich eines Ganzzahlentyps mit einem Gleitkommatyp kann die Konvertierung der Ganzzahl in Gleitkommazahl ebenfalls zu Rundungsfehlern führen.
Schließlich unterstützt Java die Verwendung von relationalen Operatoren mit anderen als den oben aufgeführten Typen. Sie können diese Operatoren beispielsweise nicht verwenden, um Zeichenfolgen, Zahlenarrays usw. zu vergleichen.