Więc dla operatorów binarnych logicznych, Java ma &
, |
, ^
, &&
i ||
.
Podsumujmy pokrótce, co robią tutaj:
- JLS 15.22.2 Operatory logiczne Boole'a &, ^ i |
- JLS 15.23 Warunek i operator &&
- JLS 15.24 Operator warunkowy lub ||
Dla
&
wartościtrue
wynikowej jest, jeśli obie wartości operandów sątrue
; w przeciwnym razie wynik tofalse
.Dla
|
wartościfalse
wynikowej jest, jeśli obie wartości operandów sąfalse
; w przeciwnym razie wynik totrue
.Dla
^
wartościtrue
wynikowej jest to, że wartości argumentów są różne; w przeciwnym razie wynik tofalse
.
&&
Operator jest jak&
ale ocenia jego prawy operand tylko wtedy, gdy wartość jego lewostronny operand jesttrue
.
||
Operator jest podobny|
, ale ocenia jego prawy operand tylko wtedy, gdy wartość jego lewostronny operand jestfalse
.
Teraz spośród wszystkich 5, 3 z nich mają złożone wersje zadania, a mianowicie |=
, &=
i ^=
. Więc moje pytanie jest oczywiste: dlaczego Java nie zapewnia &&=
i ||=
również? Uważam, że potrzebuję ich bardziej niż potrzebuję &=
i |=
.
I nie uważam, że „ponieważ jest za długi” to dobra odpowiedź, ponieważ Java tak >>>=
. Musi być lepszy powód tego zaniedbania.
Od 15.26 Operatory przypisania :
Istnieje 12 operatorów przypisania; […]
= *= /= %= += -= <<= >>= >>>= &= ^= |=
Pojawiła się uwaga, że gdyby &&=
i ||=
zostały zaimplementowane, byliby jedynymi operatorami, którzy nie oceniliby najpierw prawej strony. Uważam, że błędem jest założenie, że operator przypisania złożonego najpierw ocenia prawą stronę.
Od 15.26.2 Operatory przypisania złożonego :
Wyrażenie przypisania złożonego formularza
E1 op= E2
jest równoważne zE1 = (T)((E1) op (E2))
, gdzieT
jest typemE1
, z tą różnicą, żeE1
jest oceniane tylko raz.
Jako dowód poniższy fragment kodu zgłasza a NullPointerException
, a nie ArrayIndexOutOfBoundsException
.
int[] a = null;
int[] b = {};
a[0] += b[-1];
źródło
Odpowiedzi:
Powód
Operatory
&&=
i||=
nie są dostępne w Javie, ponieważ dla większości programistów są to:Przykład dla
&&=
Jeśli Java dopuszcza
&&=
operator, to ten kod: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
byłoby równoważne z:
bool isOk = true; if (isOK) isOk = f1(); if (isOK) isOk = f2(); //f2() is called only when f1() returns true
Ten pierwszy kod jest podatny na błędy, ponieważ wielu programistów pomyślałoby, że
f2()
zawsze jest wywoływany niezależnie od wartości zwróconej przez f1 (). To jakbool isOk = f1() && f2();
, gdzief2()
jest wywoływana tylko kiedyf1()
powrócitrue
.Jeśli programista chce,
f2()
aby wywoływano go tylko wtedy , gdyf1()
zwracatrue
, drugi kod powyżej jest mniej podatny na błędy.W przeciwnym razie
&=
wystarczy, ponieważ programista chce,f2()
aby zawsze nazywał się:Ten sam przykład, ale dla
&=
bool isOk = true; isOK &= f1(); isOK &= f2(); //f2() always called whatever the f1() returned value
Ponadto JVM powinna uruchomić powyższy kod w następujący sposób:
bool isOk = true; if (!f1()) isOk = false; if (!f2()) isOk = false; //f2() always called
Porównanie
&&
i&
wynikiCzy wyniki operatorów
&&
i są&
takie same, gdy zostaną zastosowane do wartości logicznych?Sprawdźmy, używając następującego kodu Java:
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; }
Wynik:
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 ======================
Dlatego TAK możemy zastąpić
&&
przez&
do wartości logicznych ;-)Więc lepiej użyj
&=
zamiast&&=
.To samo dotyczy
||=
Te same powody co dla
&&=
:operator
|=
jest mniej podatny na błędy niż||=
.Jeśli programista
f2()
nie chce, aby dzwoniono pof1()
powrocietrue
, radzę następujące alternatywy:// 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();
lub:
// 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 ...
źródło
&
i&&
daj te same wyniki. Dziękujemy bardzo za Twoją opinię. Podoba ci się moja odpowiedź? Twoje zdrowie.if (a) a = b
do przyspieszeniaa&=b;
jest szybszy niżif(a) a=b;
przy użyciu wartości przechowywanych w rejestrach procesora. Jeśli jednakb
znajduje się w pamięci zewnętrznej (nie jest buforowany),if(a) a=b;
jest szybszy. Czy to masz na myśli? Proszę podać więcej przykładowego kodu ;-) Ciekawi mnie Twoja opinia. Do zobaczenia. PozdrawiamisOK &&= f2();
, chciałbym, żeby tak samo jak to się&&
zwierało.A = A op B
, aby każdy doskonale wiedział, co robią i może sam zająć się konsekwencjami. Gdyby twoje powody rzeczywiście były przyczyną jego braku, uznałbym to za niechciane protekcjonalne. Chciałbym jednak podziękować za dodanie tej kwestii,bool isOk = f1() || f2() || f3() || f4();
ponieważ właśnie tak byłem oślepiony, aby zobaczyć siebie.Pewnie dlatego, że coś takiego
x = false; x &&= someComplexExpression();
wygląda na to, że powinien być przypisywany do
x
i oceniającysomeComplexExpression()
, ale fakt, że ocena zależy od wartości,x
nie wynika ze składni.Również dlatego, że składnia Javy jest oparta na języku C i nikt nie widział pilnej potrzeby dodawania tych operatorów. I tak prawdopodobnie lepiej byłoby, gdybyś miał oświadczenie if.
źródło
x() && y()
wygląda na to, że należy oceniać obie strony wyrażenia. Oczywiście ludzie akceptują, że&&
jest to zwarcie, więc powinno to również wynikać&&=
.a -= b;
działałoby zupełnie inaczej niża &&= b;
.Tak jest w Javie, bo tak jest w C.
Teraz pytanie, dlaczego tak jest w C, jest takie, ponieważ kiedy & i && stały się różnymi operatorami (kiedyś poprzedzając pochodzenie C od B), po prostu przeoczono różnorodność operatorów & =.
Ale druga część mojej odpowiedzi nie ma żadnych źródeł, które mogłyby ją potwierdzić.
źródło
Głównie dlatego, że składnia Javy jest oparta na języku C (lub przynajmniej na rodzinie C), aw języku C wszystkie te operatory przypisania są kompilowane do arytmetycznych lub bitowych instrukcji asemblera w jednym rejestrze. Wersja operatora przypisania unika tymczasowych i mogła wytworzyć bardziej wydajny kod na wczesnych nieoptymalizujących kompilatorach. Operator logiczny (jak określa się je w C) odpowiedniki (
&&=
i||=
) nie mają tak oczywistego odpowiednika z pojedynczymi instrukcjami asemblera; zwykle rozszerzają się na testową i rozgałęziającą sekwencję instrukcji.Co ciekawe, języki takie jak rubin nie posiada || = i = &&.
Edycja: terminologia różni się w językach Java i C
źródło
&
:|
i^
;&&
i||
są operatorami warunkowymi.bool
typu. To 20 lat w historii języka bez bool. Nie było powodu&&=
. wystarczyły operacje bitowe.Jednym z pierwotnych celów Javy było bycie „prostym, zorientowanym obiektowo i znajomym”. W zastosowaniu do tego przypadku & = jest znajome (C, C ++ mają to i znane w tym kontekście oznacza znajomość dla kogoś, kto zna te dwa).
&& = nie byłoby znane i nie byłoby proste w tym sensie, że projektanci języka nie chcieli myśleć o każdym operatorze, który mogliby dodać do języka, więc mniej dodatkowych operatorów jest prostszych.
źródło
Dla zmiennych boolowskich, && i || użyłby oceny zwarcia while & i | nie rób tego, więc można by oczekiwać, że && = i || = będą również używać oceny zwarć. Jest to dobry przypadek użycia. Zwłaszcza jeśli iterujesz po pętli, chcesz działać szybko, wydajnie i zwięźle.
Zamiast pisać
foreach(item in coll) { bVal = bVal || fn(item); // not so elegant }
Chcę pisać
foreach(item in coll) { bVal ||= fn(item); // elegant }
i wiedz, że gdy bVal jest prawdziwe, fn () nie będzie wywoływane w pozostałej części iteracji.
źródło
if (fn(item)) { bVal = true; break; }
.„
&
” i „&&
” nie są tym samym, co „&&
” to operacja skrótu, która nie zadziała, jeśli pierwszy operand jest fałszywy, podczas gdy „&
” i tak to zrobi (działa zarówno z liczbą, jak i wartością logiczną).Zgadzam się, że istnienie ma większy sens, ale nie jest tak źle, jeśli go nie ma. Chyba go tam nie było, ponieważ C go nie ma.
Naprawdę nie mogę myśleć, dlaczego.
źródło
Jest to dozwolone w Rubim.
Gdybym miał zgadywać, powiedziałbym, że nie jest często używany, więc nie został zaimplementowany. Innym wyjaśnieniem może być to, że parser patrzy tylko na znak przed znakiem =
źródło
Nie mogę wymyślić lepszego powodu niż „Wygląda niesamowicie brzydko!”
źródło
&&=
się za brzydkiego&
weryfikuje oba operandy, jest to operator bitowy. Java definiuje kilka operatorów bitowych, które można zastosować do typów całkowitych, long, int, short, char i byte.
&&
przestaje oceniać, jeśli pierwszy operand ma wartość false, ponieważ wynik będzie fałszywy, jest to operator logiczny. Można go zastosować do wartości logicznych.
Operator && jest podobny do operatora &, ale może sprawić, że kod będzie bardziej wydajny. Ponieważ oba wyrażenia porównywane przez operator & muszą być prawdziwe, aby całe wyrażenie było prawdziwe, nie ma powodu, aby oceniać drugie wyrażenie, jeśli pierwsze zwróci fałsz. Operator & zawsze oblicza oba wyrażenia. Operator && ocenia drugie wyrażenie tylko wtedy, gdy pierwsze wyrażenie jest prawdziwe.
Posiadanie operatora przypisania && = tak naprawdę nie dodałoby nowej funkcjonalności do języka. Arytmetyka operatora bitowego jest znacznie bardziej wyrazista, możesz wykonywać arytmetykę bitową na liczbach całkowitych, która obejmuje arytmetykę boolowską. Operatory logiczne mogą po prostu wykonywać arytmetykę boolowską.
źródło
Brian Goetz (architekt języka Java w Oracle) napisał :
źródło
a & b oraz a && b to nie to samo.
a && b jest wyrażeniem logicznym, które zwraca wartość logiczną, a a & b jest wyrażeniem bitowym, które zwraca liczbę int (jeśli a i b są liczbami int).
jak myślisz, dlaczego są takie same?
źródło