Warum hat Java keine zusammengesetzten Zuweisungsversionen der Bedingungs- und und Bedingungs- oder Operatoren? (&& =, || =)

82

Also für binäre Operatoren auf booleans, Java hat &, |, ^, &&und ||.

Fassen wir hier kurz zusammen, was sie tun:

Für &ist der Ergebniswert , truewenn beide Operanden - Werte sind true; Andernfalls ist das Ergebnis false.

Für |ist der Ergebniswert , falsewenn beide Operanden - Werte sind false; Andernfalls ist das Ergebnis true.

Für ^ist der Ergebniswert , truewenn die Operandenwerte unterschiedlich sind; Andernfalls ist das Ergebnis false.

Der &&Operator ist wie &, bewertet aber seinen rechten Operanden nur, wenn der Wert seines linken Operanden ist true.

Der ||Operator ist wie |, bewertet seinen rechten Operanden jedoch nur, wenn der Wert seines linken Operanden gleich ist false.

Nun, unter allen 5, 3 davon haben Verbindung Zuordnung Versionen, nämlich |=, &=und ^=. Meine Frage ist also offensichtlich: Warum bietet Java nicht &&=und ||=auch nicht? Ich finde, dass ich die mehr brauche als ich brauche &=und |=.

Und ich denke nicht, dass "weil es zu lang ist" eine gute Antwort ist, weil Java hat >>>=. Es muss einen besseren Grund für diese Unterlassung geben.


Ab 15.26 Zuweisungsoperatoren :

Es gibt 12 Zuweisungsoperatoren. [...]= *= /= %= += -= <<= >>= >>>= &= ^= |=


Es wurde die Bemerkung gemacht, dass wenn &&=und ||=implementiert würden, dies die einzigen Operatoren wären, die die rechte Seite nicht zuerst bewerten. Ich glaube, diese Vorstellung, dass ein zusammengesetzter Zuweisungsoperator zuerst die rechte Seite bewertet, ist ein Fehler.

Ab 15.26.2 Compound Assignment Operators :

Eine Verbindung Zuweisungsausdruck von der Form E1 op= E2entspricht E1 = (T)((E1) op (E2)), in dem Tdie Art der E1Ausnahme , dass E1nur einmal ausgewertet wird.

Als Beweis wirft das folgende Snippet ein NullPointerException, kein ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];
Polygenschmierstoffe
quelle
2
Ich gehe zum zweiten, niemand kümmert sich darum: P auch, all diese Fragen zu 'Warum ist Feature x nicht in der Sprache y?' sollte an die Designer der Sprache gebeten werden, nicht an uns: P
Federico klez Culloca
1
Was bedeutet & =? Kann mir bitte jemand sagen?
Tarik
@ Aaron: a = a & b. Es steht in der Frage
Federico klez Culloca
1
Mögliches Duplikat von Warum existiert kein "&& =" Operator?
Josh Lee
1
@jleedev: Diese Frage ist älter, aber dies hat mehr Stimmen und eingehende Links. Ich würde sagen, wenn es eine Zusammenführung gibt, füge die alte mit dieser zusammen (ja, das kann getan werden).
Polygenelubricants

Antworten:

27

Grund

Die Operatoren &&=und ||=sind auf Java nicht verfügbar, da diese Operatoren für die meisten Entwickler:

  • fehleranfällig
  • nutzlos

Beispiel für &&=

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 gleichbedeutend mit:

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, da viele Entwickler glauben, dass er f2()immer unabhängig vom zurückgegebenen Wert von f1 () aufgerufen wird. Es ist wie , bool isOk = f1() && f2();wo f2()nur , wenn sie aufgerufen wird , f1()kehrt true.

Wenn der Entwickler f2()nur bei der f1()Rückgabe aufgerufen werden möchte , ist trueder zweite Code oben weniger fehleranfällig.

Sonst reicht &=es aus, weil der Entwickler f2()immer angerufen werden möchte :

Gleiches Beispiel aber für &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

Darüber hinaus sollte die JVM diesen obigen Code wie folgt ausführen:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

Vergleichen &&und &Ergebnisse

Sind die Ergebnisse von Operatoren &&und &dieselben, wenn sie auf boolesche Werte angewendet werden?

Überprüfen wir dies mit dem folgenden Java-Code:

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
======================

Daher können wir JA&& durch &boolesche Werte ersetzen ;-)

Also besser nutzen &=statt &&=.

Gleiches gilt für ||=

Gleiche Gründe wie für &&=: Der
Bediener |=ist weniger fehleranfällig als ||=.

Wenn ein Entwickler f2()bei der f1()Rücksendung nicht angerufen werden möchte true, 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 ...
olibre
quelle
1
Hi @StriplingWarrior. Ich habe mit meinem Kollegen Yannick, unserem besten Java-Experten, gesprochen. Ich habe meine Antwort mithilfe der Java-Codequelle aktualisiert, mit der dieser Punkt überprüft wurde. Wie Sie sagten &und &&geben Sie die gleichen Ergebnisse. Vielen Dank für Ihr Feedback. Gefällt dir meine Antwort? Prost.
Olibre
2
Was ist, wenn ich das sehr schnell machen möchte? && = wäre schneller als & =, wenn es existiert, also sollten Sie if (a) a = bfür Geschwindigkeit verwenden
AdventurerOK
Hallo @adventurerOK. Entschuldigung, ich bin mir nicht sicher, was Sie meinen ... Ich denke, es a&=b;ist schneller als if(a) a=b;bei der Verwendung von Werten, die in den CPU-Registern gespeichert sind. Befindet bes sich jedoch im externen Speicher (nicht zwischengespeichert), if(a) a=b;ist dies schneller. Ist es was du meinst? Bitte geben Sie mehr Beispielcode an ;-) Ich bin gespannt auf Ihre Meinung. Wir sehen uns. Prost
olibre
12
Ich stimme nicht zu, wenn Sie sagen: "Und das wollen wir nicht." Wenn ich schreibe, isOK &&= f2();möchte ich, dass es genauso kurzschließt wie es &&tut.
Tor Klingberg
3
Ich stimme Ihrer Behauptung nicht zu, dass die Betreiber fehleranfällig oder nutzlos wären. Die Verwendung zusammengesetzter Zuweisungen ist etwas, das Sie tun, um eine Verknüpfung für das Übliche zu erstellen A = A op B, sodass jeder genau weiß, was er tut, und sich selbst um die Auswirkungen kümmern kann. Wenn Ihre Gründe tatsächlich die Ursache für seine Abwesenheit wären, würde ich es als unerwünschte Bevormundung ansehen. Ich möchte mich jedoch bei Ihnen für das Hinzufügen der Zeile bedanken, bool isOk = f1() || f2() || f3() || f4();da ich zu blind war, um mich selbst zu sehen.
Franz B.
16

Wahrscheinlich weil so etwas

x = false;
x &&= someComplexExpression();

Es sieht so aus, als ob es zugewiesen xund bewertet werden sollte someComplexExpression(), aber die Tatsache, dass die Bewertung vom Wert von xabhängt, ist aus der Syntax nicht ersichtlich.

Auch weil Javas Syntax auf C basiert und niemand die dringende Notwendigkeit sah, diese Operatoren hinzuzufügen. Mit einer if-Anweisung wären Sie wahrscheinlich sowieso besser dran.

Josh Lee
quelle
37
Ich denke, dies ist keine gute Antwort, weil man argumentieren kann, dass es so x() && y() aussieht, als ob es beide Seiten des Ausdrucks bewerten sollte. Offensichtlich akzeptieren die Leute, dass dies ein &&Kurzschluss ist, so dass dies auch folgen sollte &&=.
Polygenelubricants
2
@jleedev, stimmte zu. Ich glaube, in diesen Situationen ist es wichtig, sich daran zu erinnern, dass dies nicht das Äquivalent von x = x && someComplexExpression () ist, sondern das Äquivalent von x = someComplexExpression () && x. Die rechte Seite wird / sollte zuerst ausgewertet werden, um mit jedem anderen Zuweisungsoperator übereinzustimmen. Und angesichts dessen hätte && = kein anderes Verhalten als & =.
PSpeed
@polygene Das ist fair. Wie etwas aussieht, hängt jedoch davon ab, mit was Sie vertraut sind, und ich denke, sie wollten nichts Neues hinzufügen. Eine Sache, die ich an C / C ++ / Java / C # mag, ist, dass die grundlegende Syntax von Ausdrücken nahezu identisch ist.
Josh Lee
1
@PSpeed, du liegst falsch. Dem JLS ist sehr klar, was die zusammengesetzte Zuweisung bewirken soll. Siehe meinen Zusatz oben.
Polygenelubricants
1
@PSpeed: In diesem Fall a -= b;würde ganz anders funktionieren als a &&= b;.
David Thornley
10

Dies ist in Java so, weil es in C so ist.

Die Frage, warum dies in C so ist, ist, dass, als & und && unterschiedliche Operatoren wurden (einige Zeit vor Cs Abstieg von B), die & = Vielfalt der Operatoren einfach übersehen wurde.

Aber der zweite Teil meiner Antwort enthält keine Quellen, um sie zu sichern.

EFraim
quelle
1
Auf der lustigen Seite - die Frage wurde kürzlich im C-Forum gestellt; und diese Antwort wurde verlinkt (obwohl nicht doppelt markiert), was das Zirkelargument vervollständigt!
UKMonkey
5

Vor allem, weil die Java-Syntax auf C (oder zumindest der C-Familie) basiert und in C alle diese Zuweisungsoperatoren zu arithmetischen oder bitweisen Assemblierungsanweisungen in einem einzelnen Register kompiliert werden. Die Zuweisungsoperator-Version vermeidet temporäre und hat möglicherweise effizienteren Code für frühe nicht optimierende Compiler erzeugt. Die Äquivalente ( &&=und ||=) des logischen Operators (wie sie in C genannt werden) haben keine so offensichtliche Entsprechung zu einzelnen Montageanweisungen; Sie werden normalerweise zu einer Test- und Verzweigungssequenz von Anweisungen erweitert.

Interessanterweise Sprachen wie Ruby tun haben || = und && =.

Bearbeiten: Die Terminologie unterscheidet sich zwischen Java und C.

p00ya
quelle
Ich glaube, Sie meinen, die bedingten Operatoräquivalente haben keine so offensichtliche Entsprechung. In JLS Terminologie sind die Booleschen logischen Operatoren &, |und ^; &&und ||sind die bedingten Operatoren.
Polygenelubricants
In der C-Terminologie && und || sind "logische Operatoren", s6.5.13-14 in ISO 9899: 1999. Die bitweisen Operatoren sind nur "logisch", wenn sie auf ein einzelnes Bit angewendet werden (ein Boolescher Wert in Java). In C gibt es keinen Einzelbit-Typ, und die dortigen logischen Operatoren gelten für alle Skalartypen.
p00ya
vor C99 hatte C nicht einmal einen boolTyp. Das sind 20 Jahre in der Sprachgeschichte ohne Bool. Es gab keinen Grund dazu &&=. bitweise Operationen waren genug.
v.oddou
4

Eines der ursprünglichen Ziele von Java war es, "einfach, objektorientiert und vertraut" zu sein. In diesem Fall ist & = bekannt (C, C ++ haben es und in diesem Zusammenhang bekannt bedeutet, jemandem vertraut zu sein, der diese beiden kennt).

&& = wäre nicht vertraut und es wäre 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.

Yishai
quelle
3

Für Boolesche Variablen && und || würde eine Kurzschlussauswertung verwenden, während & und | nicht, also würden Sie erwarten, dass && = und || = auch die Kurzschlussauswertung verwenden. Hierfür gibt es einen guten Anwendungsfall. Besonders 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, sobald bVal wahr ist, fn () für den Rest der Iterationen nicht aufgerufen wird.

Zanfilip
quelle
1
Für diese Schleife möchten Sie wahrscheinlich nur tun if (fn(item)) { bVal = true; break; }.
Radiodef
2

' &' und ' &&' sind nicht dasselbe wie ' &&' 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 denke, es war nicht da, weil C es nicht hat.

Ich kann mir wirklich nicht vorstellen warum.

NawaMan
quelle
0

Es ist in Ruby erlaubt.

Wenn ich raten würde, würde ich sagen, dass es nicht häufig verwendet wird und daher nicht implementiert wurde. Eine andere Erklärung könnte sein, dass der Parser nur das Zeichen vor dem = betrachtet

zzawaideh
quelle
1
Java unterstützt << =, >> = und >>> =, so dass dies nicht unbedingt der Fall ist.
Yishai
wahr. Daran habe ich nicht gedacht. Ich denke, die einzige Erklärung ist dann, wie oft es verwendet wird.
Zzawaideh
0

Ich kann mir keinen besseren Grund vorstellen als "Es sieht unglaublich hässlich aus!"

Daniel Brückner
quelle
9
Aber dann sollte C / Java nie schön sein.
EFraim
1
Ich würde es kaum für &&=hässlich halten
7:32 Uhr
0

&

ü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.

&&

Beendet die Auswertung, wenn der erste Operand als falsch ausgewertet wird, da das Ergebnis falsch ist. Dies ist ein logischer Operator. Es kann auf Boolesche Werte angewendet werden.

Der Operator && ähnelt dem Operator &, kann jedoch Ihren Code etwas effizienter machen. Da beide vom Operator & verglichenen Ausdrücke wahr sein müssen, damit der gesamte Ausdruck wahr ist, gibt es keinen Grund, den zweiten Ausdruck auszuwerten, wenn der erste falsch zurückgibt. Der Operator & wertet immer beide Ausdrücke aus. Der Operator && wertet den zweiten Ausdruck nur 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 aussagekräftiger. Sie können eine ganzzahlige bitweise Arithmetik ausführen, einschließlich der Booleschen Arithmetik. Die logischen Operatoren können lediglich Boolesche Arithmetik ausführen.

Ely
quelle
0

Brian Goetz (Java Language Architect bei Oracle) schrieb :

https://stackoverflow.com/q/2324549/ [diese Frage] zeigt, dass Interesse an diesen Operatoren besteht und es keine klaren Argumente gibt, warum sie noch nicht existieren. Die Frage ist daher: Hat das JDK-Team in der Vergangenheit das Hinzufügen dieser Operatoren erörtert, und wenn ja, wo waren die Gründe für das Hinzufügen?

Mir ist keine spezifische Diskussion zu diesem speziellen Thema bekannt, aber wenn jemand sie vorschlagen würde, wäre die Antwort wahrscheinlich: Es ist keine unangemessene Anfrage, aber sie hat kein Gewicht.

"Das Tragen seines Gewichts" muss an seinen Kosten und Nutzen sowie an seinem Kosten-Nutzen-Verhältnis im Vergleich zu anderen Kandidatenmerkmalen gemessen werden.

Ich denke, Sie gehen implizit davon aus (mit dem Ausdruck "es gibt Zinsen"), dass die Kosten nahe Null sind und der Nutzen größer als Null ist, also scheint es ein offensichtlicher Gewinn zu sein. Dies widerlegt jedoch ein falsches Verständnis der Kosten; Eine solche Funktion wirkt sich auf die Sprachspezifikation, die Implementierung, das JCK und jedes IDE- und Java-Lehrbuch aus. Es gibt keine trivialen Sprachfunktionen. Und der Vorteil ist zwar ungleich Null, aber ziemlich gering.

Zweitens gibt es unendlich viele Funktionen , die wir konnten , aber wir nur Fähigkeit , eine Handvoll alle paar Jahre zu tun haben (und Nutzer haben eine begrenzte Fähigkeit , neue Funktionen zu absorbieren.) Also wir sehr vorsichtig sein haben , die wir wählen, wie Jedes Feature (auch ein trivial wirkendes) verbraucht einen Teil dieses Budgets und nimmt es ausnahmslos anderen weg.
Es ist nicht "warum nicht diese Funktion", sondern "welche anderen Funktionen werden wir nicht tun (oder verzögern), damit wir diese tun können, und ist das ein guter Handel?" Und ich kann mir nicht wirklich vorstellen, dass dies ein guter Handel gegen alles andere ist, an dem wir arbeiten.

Es löscht also die Messlatte für "keine schreckliche Idee" (was bereits ziemlich gut ist, viele Feature-Anfragen klären das nicht einmal), aber es ist unwahrscheinlich, dass jemals die Messlatte für "eine bessere Verwendung unseres Evolutionsbudgets" gelöscht wird als alles andere."

Marcono1234
quelle
-1

a & b und a && b sind nicht dasselbe.

a && b ist ein boolescher Ausdruck, der einen booleschen Wert 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?

Omry Yadan
quelle
1
a & b sollte im Gegensatz zu a & b immer b bewerten.
Daniel Brückner