wake-up-neo.com

Warum gibt es in Java keine zusammengesetzten Zuweisungsversionen für die Bedingungs- und/oder Bedingungsoperatoren? (&& =, || =)

Für binäre Operatoren auf Booleans hat Java also &, |, ^, && und ||.

Fassen wir kurz zusammen, was sie hier kurz machen:

Für & ist der Ergebniswert true, wenn beide Operandenwerte true sind. Andernfalls lautet das Ergebnis false.

Für | ist der Ergebniswert false, wenn beide Operandenwerte false sind. Andernfalls lautet das Ergebnis true.

Für ^ lautet der Ergebniswert true, wenn die Operandenwerte unterschiedlich sind. Andernfalls lautet das Ergebnis false.

Der &&-Operator ist wie &, wertet seinen rechten Operanden jedoch nur aus, wenn der Wert seines linken Operanden true ist.

Der ||-Operator ist wie |, wertet seinen rechten Operanden jedoch nur aus, wenn der Wert seines linken Operanden false 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 zu E1 = (T)((E1) op (E2)), wobei T der Typ von E1 ist, mit der Ausnahme, dass E1 nur einmal ausgewertet wird. 

Zum Beweis wirft das folgende Snippet eine NullPointerException und keine ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];
72

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 ä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:

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 Code wie folgt ausführen:

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

Vergleichen Sie die &&- und &-Ergebnisse

Sind 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 &&=.

Gleiches für ||=

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 ...
23
olibre

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.

16
Josh Lee

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.

8
EFraim

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

4
p00ya

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.

4
Yishai

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.

3
zanfilip

'&' 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.

2
NawaMan

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 

0
zzawaideh

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?

0
Omry Yadan

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

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.

&&

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.

0
Ely