Zwarcie operatora logicznego Java


100

Który zestaw jest zwarty i co dokładnie oznacza, że ​​złożone wyrażenie warunkowe jest zwarte?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}

Odpowiedzi:


244

&&I ||operatorzy „zwarcie”, co oznacza, że nie ocenia prawą stronę, jeśli nie jest to konieczne.

Te &i |operatorzy, stosowany jako operatorów logicznych, zawsze oceniać obie strony.

Dla każdego operatora występuje tylko jeden przypadek zwarcia i są to:

  • false && ...- nie trzeba wiedzieć, co to jest prawa strona, ponieważ wynik może być tylko falsebez względu na wartość
  • true || ...- nie trzeba wiedzieć, co to jest prawa strona, ponieważ wynik może być tylko truebez względu na wartość

Porównajmy zachowanie na prostym przykładzie:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

Druga wersja używa operatora nie powodującego zwarcia &i wyrzuci NullPointerExceptionif inputis null, ale pierwsza wersja zwróci falsebez wyjątku.


9
Chciałbym tylko trochę rozszerzyć tę odpowiedź. Operator & = jest skrótem wyrażenia x = x & i dlatego NIE powoduje zwarcia. To samo dotyczy operatora | =.
Stormcloud

11
Jedną rzecz, którą chciałbym podkreślić, | and & to operatory binarne, while && i || są operatorami warunkowymi (logicznymi). | i & pracuj nad czymś więcej niż tylko wartościami logicznymi, podczas gdy && i || działa tylko na logicznych.
Mit

1
Nie tylko nie oceniają wyrażenia po prawej stronie, ale kod nie jest wykonywany, aby było cokolwiek do oceny. Jest to krytyczny punkt zrozumienia, czy w przeciwnym razie wystąpiłby efekt uboczny.
mckenzm

@mckenzm Jaka jest różnica między oceną a wykonaniem?
Kronen

@Kronen Wykonanie może skutkować czymś więcej niż tylko oceną i skutkować efektem ubocznym, takim jak wyjątek lub opóźnienie, zapłacę nieistotne dla tego przykładu.
mckenzm

9

Zestaw A wykorzystuje operatory logiczne zwierające.

„Zwarcie” oznacza w kontekście operatorów boolowskich to, że dla zbioru wartości logicznych b1, b2, ..., bn wersje zwarciowe zaprzestaną oceny, gdy tylko pierwsza z tych wartości logicznych stanie się prawdziwa (|| ) lub fałsz (&&).

Na przykład:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)

Proszę sprecyzować, że tak jest w przypadku &&, ||działa inaczej i zaprzestanie oceny pierwszego operandu, który zwróci wartość true;)
fge

1
W rzeczywistości, aby być naprawdę kompletny, wszystko &&, ||, &i |oceniają lewej do prawej. Dla zestawu wartości logicznych b1, b2, ..., bn wersje zwarciowe przestaną oceniać, gdy pierwsza z tych wartości logicznych ma wartość true ( ||) lub false ( &&). Tak, zasada jest;)
fge

@fge: Tak, oczywiście masz rację. Twoja definicja jest doskonała niż moja. Uzupełniłem moją odpowiedź o zdanie w Twoim komentarzu. Mam nadzieję, że nie masz nic przeciwko.
afrischke

Bez obaw, wiedza nie ma wartości, jeśli się nią nie dzieli.
fge

4

Zwarcie oznacza, że ​​drugi operator nie zostanie sprawdzony, jeśli pierwszy operator zadecyduje o wyniku końcowym.

Np. Wyrażenie to: True || Fałszywe

W przypadku || potrzebujemy tylko jednej strony, aby była True. Więc jeśli lewa strona jest prawdą, nie ma sensu sprawdzać prawej strony, a zatem nie będzie to w ogóle sprawdzane.

Podobnie, fałsz i prawda

W przypadku && obie strony muszą być Prawdą. Więc jeśli lewa strona jest fałszywa, nie ma sensu sprawdzać prawej strony, odpowiedź musi być fałszywa. I stąd w ogóle nie będzie to sprawdzane.


4
boolean a = (x < z) && (x == x);

Ten rodzaj spowoduje zwarcie, co oznacza, że ​​jeśli (x < z)oszacuje jako fałsz, to ten ostatni nie zostanie oceniony, abędzie fałszywy, w przeciwnym razie &&również oceni (x == x).

& jest operatorem bitowym, ale także operatorem logicznym AND, który nie powoduje zwarcia.

Możesz je przetestować w następujący sposób (zobacz, ile razy metoda jest wywoływana w każdym przypadku):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}

-1 Twoja odpowiedź sugeruje, że &jest to tylko operator bitowy, ale to nieprawda. Jest to również operator logiczny „lub”.
Bohemian

@Bohemian: Dzięki za ostrzeżenie. true & falseocenia jako fałsz. Czy możesz wyjaśnić ten „boolowski” lub „operator”? Może nie rozumiem tego, co próbujesz powiedzieć.
Bhesh Gurung

Przepraszam - miałem na myśli boolean AND, nie OR! ie true & falsejest poprawną składnią. -1 usunięto :)
Bohemian

4

Mówiąc najprościej, zwarcie oznacza zatrzymanie oceny, gdy wiesz, że odpowiedź nie może się już zmienić. Na przykład, jeśli oceniasz łańcuch logicznych ANDs i odkryjesz FALSEpośrodku tego łańcucha, wiesz, że wynik będzie fałszywy, bez względu na wartości pozostałych wyrażeń w łańcuchu. To samo dotyczy łańcucha ORs: gdy odkryjesz a TRUE, od razu znasz odpowiedź, więc możesz pominąć ocenę pozostałych wyrażeń.

Wskazujesz Javie, że chcesz skracać, używając &&zamiast &i ||zamiast |. Pierwszy zestaw w Twoim poście to zwarcie.

Zauważ, że to więcej niż próba zaoszczędzenia kilku cykli procesora: w takich wyrażeniach

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

zwarcie oznacza różnicę między poprawnym działaniem a awarią (w przypadku, gdy mystring jest zerowe).


2

Java udostępnia dwa interesujące operatory logiczne, których nie ma w większości innych języków komputerowych. Te wtórne wersje AND i OR są znane jako operatory logiczne zwarcia . Jak widać z poprzedniej tabeli, operator OR daje w wyniku prawdę, gdy A jest prawdziwe, bez względu na to, jakie jest B.

Podobnie operator AND daje w wyniku fałsz, gdy A jest fałszywe, bez względu na to, jakie jest B. Jeśli używasz formularzy ||i &&, zamiast |i& formy tych operatorów, Java nie przeszkadza, aby ocenić prawy operand sam. Jest to bardzo przydatne, gdy operand po prawej stronie zależy od tego, czy lewy jest prawdą lub fałszem, aby działał poprawnie.

Na przykład poniższy fragment kodu pokazuje, w jaki sposób można skorzystać z oceny logicznej zwarcia, aby upewnić się, że operacja dzielenia będzie prawidłowa przed jej oceną:

if ( denom != 0 && num / denom >10)

Ponieważ &&używana jest forma zwarcia funkcji AND ( ), nie ma ryzyka spowodowania wyjątku w czasie wykonywania od dzielenia przez zero. Gdyby ten wiersz kodu został napisany przy użyciu pojedynczej &wersji AND, obie strony musiałyby zostać ocenione, powodując wyjątek w czasie wykonywania, gdy denomwynosi zero.

Standardową praktyką jest stosowanie zwarciowych form AND i OR w przypadkach związanych z logiką Boole'a, pozostawiając wersje jednoznakowe wyłącznie dla operacji bitowych. Są jednak wyjątki od tej reguły. Weźmy na przykład pod uwagę następującą instrukcję:

 if ( c==1 & e++ < 100 ) d = 100;

Tutaj użycie pojedynczej &zapewnia, że ​​operacja przyrostu zostanie zastosowana do etego, czy cjest równa 1, czy nie.


2

Logiczne LUB: - zwraca prawdę, jeśli przynajmniej jeden z operandów ma wartość true. Oba operandy są oceniane przed zastosowaniem operatora OR.

Short Circuit OR: - jeśli operand po lewej stronie zwraca prawdę, zwraca prawdę bez szacowania argumentu po prawej stronie.


2

Istnieje kilka różnic między operatorami &i &&. Te same różnice dotyczą |i ||. Najważniejszą rzeczą, o której należy pamiętać, jest to, że &&jest to operator logiczny , który ma zastosowanie tylko do operandów boolowskich, a& jest to operator bitowy , który ma zastosowanie zarówno do typów całkowitych, jak i logicznych.

Za pomocą operacji logicznej można wykonać zwarcie, ponieważ w pewnych przypadkach (jak pierwszy operand &&bytu falselub pierwszy operand funkcji|| bytu true) nie musisz oceniać reszty wyrażenia. Jest to bardzo przydatne do wykonywania takich czynności, jak sprawdzanie nullprzed uzyskaniem dostępu do pola lub metody oraz sprawdzanie potencjalnych zer przed podzieleniem przez nie. W przypadku wyrażenia złożonego każda część wyrażenia jest oceniana rekurencyjnie w ten sam sposób. Na przykład w następującym przypadku:

(7 == 8) || ( (1 == 3) && (4 == 4))

Oceniane będą tylko zaznaczone fragmenty. Aby obliczyć ||, najpierw sprawdź, czy 7 == 8jest true. Gdyby tak było, prawa strona zostałaby całkowicie pominięta. Prawa strona sprawdza tylko, czy 1 == 3jest false. Ponieważ tak jest, 4 == 4nie trzeba go sprawdzać, a wynikiem całego wyrażenia jest false. Gdyby lewa strona była truenp. 7 == 7Zamiast 7 == 8, cała prawa strona zostałaby pominięta, ponieważ całość|| wyrażenie byłoby trueniezależnie.

W przypadku operacji bitowych musisz oszacować wszystkie operandy, ponieważ tak naprawdę po prostu łączysz bity. Booleany są w rzeczywistości jednobitowymi liczbami całkowitymi w Javie (niezależnie od tego, jak działają elementy wewnętrzne) i to tylko zbieg okoliczności, że w tym jednym szczególnym przypadku można wykonać zwarcia dla operatorów bitowych. Powodem, dla którego nie można zwierać ogólnej liczby całkowitej &lub |operacji, jest to, że niektóre bity mogą być włączone, a niektóre wyłączone w którymkolwiek z argumentów. Coś jak 1 & 2daje zero, ale nie możesz tego wiedzieć bez oceny obu operandów.


1
if(demon!=0&& num/demon>10)

Ponieważ używana jest forma zwarcia AND (&&), nie ma ryzyka spowodowania wyjątku w czasie wykonywania, gdy demon ma wartość zero.

Nr ref. Java 2 Fifth Edition autorstwa Herberta Schildta

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.