Für binäre Operatoren auf Booleans hat Java also &
, |
, ^
, &&
und ||
.
Fassen wir kurz zusammen, was sie hier kurz machen:
Für
&
ist der Ergebniswerttrue
, wenn beide Operandenwertetrue
sind. Andernfalls lautet das Ergebnisfalse
.Für
|
ist der Ergebniswertfalse
, wenn beide Operandenwertefalse
sind. Andernfalls lautet das Ergebnistrue
.Für
^
lautet der Ergebniswerttrue
, wenn die Operandenwerte unterschiedlich sind. Andernfalls lautet das Ergebnisfalse
.Der
&&
-Operator ist wie&
, wertet seinen rechten Operanden jedoch nur aus, wenn der Wert seines linken Operandentrue
ist.Der
||
-Operator ist wie|
, wertet seinen rechten Operanden jedoch nur aus, wenn der Wert seines linken Operandenfalse
ist.
Nun, von allen 5 haben 3 davon zusammengesetzte Zuweisungsversionen, nämlich |=
, &=
und ^=
. Meine Frage ist also offensichtlich: Warum bietet Java nicht auch &&=
und ||=
an? Ich finde, dass ich diese mehr brauche als &=
und |=
.
Und ich glaube nicht, dass "weil es zu lang ist", eine gute Antwort ist, weil Java >>>=
hat. Es muss einen besseren Grund für diese Auslassung geben.
Von 15.26 Zuweisungsoperatoren :
Es gibt 12 Zuweisungsoperatoren. [...]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
Es wurde der Kommentar gemacht, dass, wenn &&=
und ||=
implementiert würden, die einzigen Operatoren die rechte Seite nicht zuerst auswerten würden. Ich glaube, diese Vorstellung, dass ein zusammengesetzter Zuweisungsoperator zuerst die rechte Seite auswertet, ist ein Fehler.
Ab 15.26.2 Operatoren für zusammengesetzte Zuweisungen :
Ein zusammengesetzter Zuweisungsausdruck des Formulars
E1 op= E2
ist äquivalent zuE1 = (T)((E1) op (E2))
, wobeiT
der Typ vonE1
ist, mit der Ausnahme, dassE1
nur einmal ausgewertet wird.
Zum Beweis wirft das folgende Snippet eine NullPointerException
und keine ArrayIndexOutOfBoundsException
.
int[] a = null;
int[] b = {};
a[0] += b[-1];
Die Operatoren &&=
und ||=
sind auf Java nicht verfügbar, da diese Operatoren für die meisten Entwickler:
&&=
Wenn Java den &&=
-Operator erlaubt, dann dieser Code:
bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value
wäre äquivalent zu:
bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true
Dieser erste Code ist fehleranfällig , weil viele Entwickler denken, dass f2()
immer aufgerufen wird, wie auch immer der von f1 () zurückgegebene Wert lautet. Es ist wie bool isOk = f1() && f2();
, wo f2()
nur aufgerufen wird, wenn f1()
true
zurückgibt.
Wenn der Entwickler möchte, dass f2()
nur aufgerufen wird, wenn f1()
true
zurückgibt, ist der obige zweite Code weniger fehleranfällig.
Andernfalls ist &=
ausreichend, da der Entwickler möchte, dass f2()
immer aufgerufen wird:
&=
bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value
Darüber hinaus sollte die JVM diesen Code wie folgt ausführen:
bool isOk = true;
if (!f1()) isOk = false;
if (!f2()) isOk = false; //f2() always called
&&
- und &
-ErgebnisseSind die Ergebnisse der Operatoren &&
und &
gleich, wenn sie auf boolesche Werte angewendet werden?
Lassen Sie uns dies mit folgendem Java-Code überprüfen:
public class qalcdo {
public static void main (String[] args) {
test (true, true);
test (true, false);
test (false, false);
test (false, true);
}
private static void test (boolean a, boolean b) {
System.out.println (counter++ + ") a=" + a + " and b=" + b);
System.out.println ("a && b = " + (a && b));
System.out.println ("a & b = " + (a & b));
System.out.println ("======================");
}
private static int counter = 1;
}
Ausgabe:
1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================
YESwir können &&
durch &
für boolesche Werte ersetzen ;-)
Verwenden Sie also besser &=
anstelle von &&=
.
||=
Gleiche Gründe wie für &&=
:
Operator |=
ist weniger fehleranfällig als ||=
.
Wenn ein Entwickler möchte, dass f2()
nicht aufgerufen wird, wenn f1()
true
zurückgibt, empfehle ich die folgenden Alternativen:
// here a comment is required to explain that
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();
oder:
// here the following comments are not required
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...
Vermutlich weil so was
x = false;
x &&= someComplexExpression();
Sieht aus wie es sollte x
zugewiesen werden und someComplexExpression()
ausgewertet werden, aber die Tatsache, dass die Bewertung vom Wert von x
abhängt, ist aus der Syntax nicht ersichtlich.
Auch weil die Syntax von Java auf C basiert und niemand die Notwendigkeit sah, diese Operatoren hinzuzufügen. Mit einer if-Anweisung wären Sie wahrscheinlich besser dran.
In Java ist das so, weil es in C so ist.
Nun ist die Frage, warum es in C so ist, weil, wenn & und && zu anderen Operatoren wurden (irgendwann vor Cs Abstieg von B), die Vielfalt der Operatoren & = einfach übersehen wurde.
Der zweite Teil meiner Antwort hat jedoch keine Quellen, die dies unterstützen.
Hauptsächlich, weil die Java-Syntax auf C (oder zumindest auf der C-Familie) basiert, und in C werden all diese Zuweisungsoperatoren zu arithmetischen oder bitweisen Assembly-Anweisungen in einem einzigen Register kompiliert. Die Zuweisungsoperator-Version vermeidet temporäre Vorgänge und hat auf frühen nichtoptimierenden Compilern möglicherweise effizienteren Code erzeugt. Die Entsprechungen des logischen Operators (wie sie in C bezeichnet werden) (&&=
und ||=
) haben keine offensichtliche Entsprechung zu einzelnen Assembly-Anweisungen. Sie erweitern sich normalerweise zu einer Test- und Verzweigungssequenz von Anweisungen.
Interessanterweise haben Sprachen wie Ruby do || = und && =.
Bearbeiten: Die Terminologie unterscheidet sich zwischen Java und C
Eines von Javas ursprünglichen Zielen sollte "einfach, objektorientiert und vertraut" sein. Wie in diesem Fall angewendet, ist & = vertraut (C und C++ haben es in diesem Zusammenhang mit jemandem vertraut, der diese beiden kennt).
&& = wäre nicht vertraut und nicht einfach in dem Sinne, dass die Sprachdesigner nicht an jeden Operator denken wollten, den sie der Sprache hinzufügen könnten, so dass weniger zusätzliche Operatoren einfacher sind.
Für boolesche Variablen, && und || würde Kurzschlussauswertung verwenden, während & und | Nicht, also würden Sie erwarten, dass && = und || = auch die Kurzschlussauswertung verwenden. Dafür gibt es einen guten Anwendungsfall. Insbesondere wenn Sie über eine Schleife iterieren, möchten Sie schnell, effizient und knapp sein.
Anstatt zu schreiben
foreach(item in coll)
{
bVal = bVal || fn(item); // not so elegant
}
Ich möchte schreiben
foreach(item in coll)
{
bVal ||= fn(item); // elegant
}
und wissen, dass, wenn bVal wahr ist, fn () für den Rest der Iterationen nicht aufgerufen wird.
'&
' und '&&
' sind nicht identisch mit '&&
'. Dies ist eine Abkürzungsoperation, die nicht ausgeführt wird, wenn der erste Operand falsch ist, während '&
' dies trotzdem tut (funktioniert sowohl mit number als auch mit boolean).
Ich stimme zu, dass es sinnvoller ist zu existieren, aber es ist nicht so schlimm, wenn es nicht da ist. Ich glaube, es war nicht da, weil C es nicht hat.
Kann mir wirklich nicht vorstellen warum.
Es ist in Ruby erlaubt.
Wenn ich raten würde, würde ich sagen, dass es nicht häufig verwendet wird, also nicht implementiert wurde. Eine andere Erklärung könnte sein, dass der Parser nur das Zeichen vor dem = betrachtet
a & b und a && b sind nicht dasselbe.
a && b ist ein boolescher Ausdruck, der einen booleschen Ausdruck zurückgibt, und a & b ist ein bitweiser Ausdruck, der ein int zurückgibt (wenn a und b ints sind).
was denkst du, sind sie gleich?
Ich kann mir keinen besseren Grund vorstellen als "Es sieht unglaublich hässlich aus!"
&
überprüft beide Operanden, es ist ein bitweiser Operator. Java definiert mehrere bitweise Operatoren, die auf die Ganzzahltypen long, int, short, char und byte angewendet werden können.
&&
stoppt die Auswertung, wenn der erste Operand falsch ist, da das Ergebnis falsch ist, es ist ein logischer Operator. Es kann auf Booleans angewendet werden.
Der Operator && ist dem Operator & ähnlich, kann jedoch den Code etwas effizienter machen. Da beide Ausdrücke mit dem Operator & verglichen werden müssen, damit der gesamte Ausdruck wahr ist, gibt es keinen Grund, den zweiten Ausdruck auszuwerten, wenn der erste falsch ergibt. Der Operator & wertet immer beide Ausdrücke aus. Der Operator && wertet den zweiten Ausdruck nur dann aus, wenn der erste Ausdruck wahr ist.
Ein && = Zuweisungsoperator würde der Sprache nicht wirklich neue Funktionen hinzufügen. Die Arithmetik des bitweisen Operators ist viel ausdrucksvoller. Sie können auch eine bitweise Ganzzahl-Arithmetik ausführen, zu der auch die boolesche Arithmetik gehört. Die logischen Operatoren können lediglich Boolesche Arithmetik ausführen.