Różnice w operatorach logicznych: & vs && i | vs ||

Odpowiedzi:

134

Są to operatory bitowe AND i bitowe OR.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

Podziękowania dla Carlosa za wskazanie odpowiedniej sekcji w specyfikacji języka Java ( 15.22.1 , 15.22.2 ) dotyczącej różnych zachowań operatora na podstawie jego danych wejściowych.

Rzeczywiście, gdy oba wejścia są logiczne, operatory są uważane za logiczne operatory boolowskie i zachowują się podobnie do operatorów warunkowych-i ( &&) i warunkowych-lub ( ||) z wyjątkiem faktu, że nie powodują zwarcia, więc poniższe jest bezpieczne :

if((a != null) && (a.something == 3)){
}

To nie jest:

if((a != null) & (a.something == 3)){
}

„Zwarcie” oznacza, że ​​operator niekoniecznie sprawdza wszystkie warunki. W powyższych przykładach, &&sprawdzi drugi warunek tylko wtedy, gdy anie jest null(w przeciwnym razie cała instrukcja zwróci fałsz, a zatem i tak byłoby dyskusyjne sprawdzenie następujących warunków), więc stwierdzenie a.somethingnie spowoduje wyjątku lub jest uważane za „bezpieczne . ”

&Operatora zawsze sprawdza każdy stan w klauzuli więc w powyższych przykładach, a.somethingmożna ocenić, kiedy aw rzeczywistości jest nullto wartość, zwiększając wyjątek.

Justin Niessner
źródło
1
chciałem wyjaśnić ... i zwróci 1 tylko wtedy, gdy OBA to 1? Więc 101 i 001 to 001? Dobrze?
gideon,
@giddy @Jonathon - Zaktualizowałem moje wartości, aby lepiej pokazać tę sytuację.
Justin Niessner,
niekompletne: są również operatorami LOGICZNYMI (dla wartości logicznych).
user85421
1
@ Carlos- Nie. Nadal są operatorami bitowymi. Po prostu zachowują się tak samo, jak nie powodujące zwarcia operatory logiczne. Jest różnica.
Justin Niessner,
4
a jakie są niekrotne operatory logiczne? Operatory & i | (zadawane przez OP) to „Integer Bitwise Operators” (JLS 15.22.1) i „Boolean Logical Operators” (JLS 15.22.2). A może specyfikacja języka Java jest błędna?
user85421
108

Myślę, że mówisz o logicznym znaczeniu obu operatorów, tutaj masz podsumowanie tabeli:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

Ocena zwarcia, ocena minimalna lub ocena McCarthy'ego (za Johnem McCarthym) to semantyka niektórych operatorów logicznych w niektórych językach programowania, w których drugi argument jest wykonywany lub szacowany tylko wtedy, gdy pierwszy argument nie wystarcza do określenia wartości argumentu wyrażenie: kiedy pierwszy argument funkcji AND ma wartość fałsz, ogólna wartość musi być fałszywa; a kiedy pierwszy argument funkcji LUB ma wartość true, ogólna wartość musi być prawdziwa.

Not Safe oznacza, że ​​operator zawsze sprawdza każdy warunek w klauzuli, więc w powyższych przykładach 1 / x może zostać oszacowane, gdy x jest w rzeczywistości wartością 0, co powoduje wyjątek.

Torres
źródło
1
@Torres - Proszę rozszerzyć swoją odpowiedź, wyjaśniając „krótkie spięcie” i „bezpieczne”. Czy „wyłączne lub” i „logiczne nie” również „nie powodują zwarcia”? I dlaczego nazywa się to „logiczne nie” zamiast „logiczne nie logiczne”? I dlaczego „logiczne NIE” nie jest zgrupowane z „logicznym AND” i „logicznym OR”? Dobra odpowiedź, ale wymaga pracy.
tfmontague
@tfmontague, wyjaśniłem, co oznacza zwarcie (edytując tę ​​odpowiedź) .. Czekam, aż moja zmiana zostanie „zrecenzowana”.
Taslim Oseni
co jest „niebezpieczne” w braku zwarcia? czy nie powinno być bezpieczniej niż używanie zwarć? btw: tak naprawdę nie wyjaśniasz terminu „zwarcie”. oznacza to, że przy "braku zwarcia" wszystkie części są najpierw oceniane, następnie stosowana jest operacja boolowska, natomiast przy zwarciu ocena jest zatrzymywana, gdy pierwsze wyrażenie spełnia warunek, np. (a || b) nie oceń b, jeśli a jest prawdziwe, a operacja lub zwróci wartość true, bez względu na to, jakie jest b.
SCI
26

Wiem, że jest tu wiele odpowiedzi, ale wszystkie wydają się nieco zagmatwane. Po przeprowadzeniu pewnych badań z przewodnika do nauki języka Java, opracowałem trzy różne scenariusze, kiedy używać && lub &. Trzy scenariusze to logiczne AND , bitowe AND i logiczne AND .

ORAZ logiczne: ORAZ logiczne (aka ORAZ warunkowe) używa operatora && . To skrótowe znaczenie: jeśli lewy operand jest fałszywy, to prawy operand nie będzie oceniany.
Przykład:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

W powyższym przykładzie wartość wypisywana na konsoli x będzie wynosić 0, ponieważ pierwszy operand w instrukcji if jest fałszywy, stąd java nie ma potrzeby obliczania (1 == ++ x), dlatego x nie zostanie obliczone.

Bitowe AND: Bitowe AND używa operatora & . Służy do wykonywania operacji bitowej na wartości. O wiele łatwiej jest zobaczyć, co się dzieje, patrząc na operacje na liczbach binarnych, np .:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

Jak widać na przykładzie, gdy binarne reprezentacje liczb 5 i 12 są ustawione w jednej linii, wówczas preformowane bitowe AND da tylko liczbę binarną, w której ta sama cyfra w obu liczbach będzie miała 1. Stąd 0101 i 1100 == 0100. Która dziesiętnie to 5 i 12 == 4.

Boolean AND: Teraz logiczny operator AND zachowuje się podobnie i inaczej zarówno w przypadku bitowego AND, jak i logicznego AND. Lubię o tym myśleć jako o wykonywaniu bitowego AND pomiędzy dwiema wartościami logicznymi (lub bitami), dlatego używa operatora & . Wartości logiczne mogą być również wynikiem wyrażenia logicznego.

Zwraca wartość true lub false, podobnie jak logiczne AND, ale w przeciwieństwie do logicznego AND nie jest zwarty. Powodem jest to, że aby wykonać to bitowe AND, musi znać wartość zarówno lewego, jak i prawego operandu. Oto były:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

Teraz, gdy instrukcja if zostanie uruchomiona, wyrażenie (1 == ++ x) zostanie wykonane, nawet jeśli lewy operand jest fałszywy. Stąd wartość wydrukowana dla x będzie wynosić 1, ponieważ została zwiększona.

Dotyczy to również logicznego OR (||), bitowego OR (|) i logicznego OR (|) Mam nadzieję, że to wyjaśni pewne nieporozumienia.

LynchburgExplorer
źródło
to preform that bitwise AND, it must know the value of both left and right operandsNie brzmi to dla mnie dobrze. Aby wykonać BITWISE ANDoperand, nie musisz znać właściwego operandu, aby móc obliczyć wynik, jeśli lewy operand jest FALSE. Co pan wyjaśnić jest poprawna, ale rozumowanie Ci państwo nie wydaje się więc, przynajmniej dla mnie ..
Koray Tugay
7

Operatory && i || powodują zwarcia, co oznacza, że ​​nie będą oceniać wyrażenia po prawej stronie, jeśli wartość wyrażenia po lewej stronie jest wystarczająca do określenia wyniku.

Tassos Bassoukos
źródło
7
-1 za powiedzenie OP, co już wiedział, i brak odpowiedzi na pytanie, które faktycznie zadał.
Alnitak
5

& i | zapewniają taki sam wynik jak && i || operatorzy. Różnica polega na tym, że zawsze oceniają obie strony wyrażenia, gdzie jako && i || przestań oceniać, czy pierwszy warunek wystarczy, aby określić wynik.

Brian Scott
źródło
1
Źle .... Ponieważ &&ocenia oba wyniki, a ||zwraca tylko wtedy, gdy pierwszy warunek jest prawdziwy.
Buhake Sindi,
1
Co? && oblicza prawą stronę wyrażenia tylko wtedy, gdy po lewej stronie jest już prawdą. W przeciwnym razie przestaje oceniać, ponieważ pierwsza fałszywa implicite oznacza, że ​​wynik nie może być prawdziwy. Zobacz jguru.com/faq/view.jsp?EID=16530
Brian Scott,
1
( 2 & 4 )szacuje do false, podczas gdy ( 2 && 4 )szacuje do true. Jak dokładnie to jest ten sam wynik?
Piskvor opuścił budynek
1
@Piskvor - nie w Javie! 2 & 4daje w wyniku liczbę całkowitą, a nie wartość logiczną (w tym przypadku zero). 2 && 4nie kompiluje && akceptuje tylko wartości logiczne. Java nie pozwala na mieszanie wartości logicznych i ints: zero nie jest false, falsenie jest zero ...
user85421
1
@BuhakeSindi Wrong. Ponieważ &&oblicza drugi operand tylko wtedy, gdy pierwszy operand jest true.
Markiz Lorne
2

W Javie pojedyncze operatory &, |, ^,! zależą od operandów. Jeśli oba operandy są liczbami całkowitymi, wykonywana jest operacja bitowa. Jeśli oba są wartościami logicznymi, wykonywana jest operacja „logiczna”.

Jeśli oba operandy są niezgodne, zgłaszany jest błąd czasu kompilacji.

Podwójne operatory &&, || zachowują się podobnie do swoich pojedynczych odpowiedników, ale oba operandy muszą być wyrażeniami warunkowymi, na przykład:

if ((a <0) && (b <0)) {...} lub podobnie, if ((a <0) || (b <0)) {...}

źródło: programowanie java lang 4th ed

aaron s.
źródło
1

Może warto wiedzieć, że bitowe operatory AND i bitowe OR są zawsze oceniane przed warunkowym AND i warunkowym OR, używanymi w tym samym wyrażeniu.

if ( (1>2) && (2>1) | true) // false!
alexmeia
źródło
1
czy masz na myśli priorytet operatora, a nie kolejność oceny? Wolałbym nie widzieć różnicy priorytetów używanej w prawdziwym kodzie. W tym celu użyj nawiasów zamiast operatorów bitowych.
John Dvorak
1

&&; || są operatorami logicznymi… zwarciem

&; | są logicznymi operatorami logicznymi .... Bez zwarć

Przechodzenie do różnic w wykonywaniu wyrażeń. Operatory bitowe oceniają obie strony niezależnie od wyniku lewej strony. Ale w przypadku obliczania wyrażeń za pomocą operatorów logicznych ocena wyrażenia prawej ręki zależy od stanu lewej ręki.

Na przykład:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

To wypisze i = 26; j = 25, Ponieważ pierwszy warunek jest fałszywy, stan prawej ręki jest pomijany, ponieważ wynik i tak jest fałszywy, niezależnie od stanu prawej strony. (zwarcie)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Ale to wypisze i = 26; j = 26,

Nickhil
źródło
0

Jeśli wyliczane jest wyrażenie zawierające operator boolowski & , oceniane są oba operandy. Następnie operator & jest stosowany do operandu.

Podczas obliczania wyrażenia zawierającego operator && obliczany jest pierwszy operand. Jeśli wynik pierwszego operandu to fałsz, ocena drugiego argumentu jest pomijana.

Jeśli pierwszy operand zwraca wartość true, to obliczany jest drugi operand. Jeśli drugi operand zwraca wartość true, wówczas operator && jest następnie stosowany do pierwszego i drugiego operandu.

Podobne dla | i ||.

RishiKesh Pathak
źródło
0

Chociaż podstawową różnicą jest to, że &jest używany do operacji bitowe głównie na long, intlub bytegdzie może on być stosowany do rodzaju maski, wyniki mogą się różnić, nawet jeśli używać go zamiast logiczne &&.

Różnica jest bardziej zauważalna w niektórych scenariuszach:

  1. Ocena niektórych wyrażeń jest czasochłonna
  2. Ocena jednego wyrażenia może być wykonana tylko wtedy, gdy poprzednie było prawdziwe
  3. Wyrażenia mają pewien efekt uboczny (zamierzone lub nie)

Pierwsza kwestia jest dość prosta, nie powoduje żadnych błędów, ale zajmuje więcej czasu. Jeśli masz kilka różnych sprawdzeń w jednej instrukcji warunkowej, umieść te, które są tańsze lub z większym prawdopodobieństwem zawiodą, po lewej stronie.

Po drugie, zobacz ten przykład:

if ((a != null) & (a.isEmpty()))

To się nie powiedzie null, ponieważ ocena drugiego wyrażenia daje NullPointerException. Operator logiczny &&jest leniwy, jeśli lewy operand jest fałszywy, wynik jest fałszywy, niezależnie od tego, jaki jest prawy operand.

Przykład trzeciego punktu - powiedzmy, że mamy aplikację, która korzysta z DB bez żadnych wyzwalaczy ani kaskad. Zanim usuniemy obiekt budynku, musimy zmienić budynek obiektu działu na inny. Powiedzmy też, że status operacji jest zwracany jako wartość logiczna (prawda = sukces). Następnie:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

Spowoduje to ocenę obu wyrażeń, a tym samym usuwa kompilację, nawet jeśli aktualizacja działu nie powiodła się z jakiegoś powodu. Dzięki &&temu działa zgodnie z przeznaczeniem i zatrzymuje się po pierwszej awarii.

Jeśli chodzi o a || bto, jest to równoważne !(!a && !b), zatrzymuje się, jeśli ajest prawdziwe, nie potrzeba więcej wyjaśnień.

Vlasec
źródło