Mam do zrobienia w Javie długi zestaw porównań i chciałbym wiedzieć, czy jedno lub więcej z nich okaże się prawdą. Ciąg porównań był długi i trudny do odczytania, więc podzieliłem go ze względu na czytelność i automatycznie przeszedłem do użycia operatora skrótu |=
zamiast negativeValue = negativeValue || boolean
.
boolean negativeValue = false;
negativeValue |= (defaultStock < 0);
negativeValue |= (defaultWholesale < 0);
negativeValue |= (defaultRetail < 0);
negativeValue |= (defaultDelivery < 0);
Oczekuję, negativeValue
że będzie prawdziwe, jeśli którakolwiek z domyślnych wartości <coś> jest ujemna. Czy to jest ważne? Czy zrobi to, czego oczekuję? Nie widziałem tego wspomnianego w witrynie Sun ani w stosie, ale wydaje się, że Eclipse nie ma z tym problemu, a kod kompiluje się i działa.
Podobnie, gdybym chciał wykonać kilka logicznych przecięć, czy mógłbym użyć &=
zamiast &&
?
java
assignment-operator
compound-assignment
or-operator
David Mason
źródło
źródło
||=
operatora, ale|=
jest to kombinacja operatora bitowego lub.|=
zwarcia byłoby niespójne z innymi operatorami przypisania złożonego, ponieważa |= b;
nie byłoby takie samo jaka = a | b;
, ze zwykłym zastrzeżeniem dotyczącyma
dwukrotnego oceniania (jeśli ma to znaczenie). Wydaje mi się, że nie podjęto decyzji dotyczącej dużego języka||=
, więc nie rozumiem.Odpowiedzi:
|=
To operatorowi przypisanie związek ( na trasę 15.26.2 ) do logicznej operator logiczny|
( na trasę 15.22.2 ); nie mylić z warunkowym lub||
( JLS 15.24 ). Istnieją również&=
i^=
odpowiadające złożonej wersji przypisania logiki boolowskiej&
i^
odpowiednio.Innymi słowy
boolean b1, b2
, te dwa są równoważne:Różnica między operatorami logicznymi (
&
i|
) w porównaniu z ich odpowiednikami warunkowymi (&&
i||
) polega na tym, że te pierwsze nie powodują „zwarcia”; to drugie. To jest:&
i|
zawsze obliczaj oba operandy&&
i warunkowo||
oceniać właściwy operand ; prawy operand jest oceniany tylko wtedy, gdy jego wartość mogłaby wpłynąć na wynik operacji binarnej. Oznacza to, że prawy operand NIE jest oceniany, gdy:&&
szacuje dofalse
false
)||
szacuje dotrue
true
)Wracając do pierwotnego pytania, tak, ta konstrukcja jest prawidłowa i chociaż
|=
nie jest dokładnie równoważnym skrótem dla=
i||
, oblicza to, czego chcesz. Ponieważ prawa strona|=
operatora w twoim użyciu jest prostą operacją porównywania liczb całkowitych, fakt, że|
nie powoduje zwarcia, jest nieistotny.Zdarzają się przypadki, w których zwarcie jest pożądane, a nawet wymagane, ale Twój scenariusz nie jest jednym z nich.
Szkoda, że w przeciwieństwie do niektórych innych języków Java nie ma
&&=
i||=
. Zostało to omówione w pytaniu Dlaczego Java nie ma złożonych wersji przypisania operatorów warunkowych i warunkowych lub? (&& =, || =) .źródło
|
Nie jest to operator „skrótu” (lub zwarcia) w taki sposób, że || i && są (w tym sensie, że nie ocenią RHS, jeśli już znają wynik na podstawie LHS), ale zrobią to, co chcesz pod względem pracy .
Jako przykład różnicy, ten kod będzie dobrze, jeśli
text
ma wartość null:boolean nullOrEmpty = text == null || text.equals("")
ale to nie będzie:
boolean nullOrEmpty = false; nullOrEmpty |= text == null; nullOrEmpty |= text.equals(""); // Throws exception if text is null
(Oczywiście możesz to zrobić
"".equals(text)
w tym konkretnym przypadku - próbuję tylko zademonstrować zasadę).źródło
Możesz mieć tylko jedno stwierdzenie. Wyrażony w wielu wierszach, czyta prawie dokładnie tak, jak przykładowy kod, tylko mniej konieczne:
boolean negativeValue = defaultStock < 0 | defaultWholesale < 0 | defaultRetail < 0 | defaultDelivery < 0;
W przypadku najprostszych wyrażeń użycie
|
może być szybsze niż||
dlatego, że nawet jeśli pozwala uniknąć porównania, oznacza to niejawne użycie gałęzi, a to może być wielokrotnie droższe.źródło
Chociaż może to być przesada dla twojego problemu, biblioteka Guava ma fajną składnię z
Predicate
s i dokonuje oceny zwarć i / iPredicate
s.Zasadniczo porównania są przekształcane w obiekty, pakowane w kolekcję, a następnie powtarzane. Dla lub predykaty, pierwsze prawdziwe trafienie wraca z iteracji i odwrotnie dla i.
źródło
Jeśli chodzi o czytelność, mam koncepcję oddzielenia testowanych danych od logiki testowania. Przykład kodu:
// declare data DataType [] dataToTest = new DataType[] { defaultStock, defaultWholesale, defaultRetail, defaultDelivery } // define logic boolean checkIfAnyNegative(DataType [] data) { boolean negativeValue = false; int i = 0; while (!negativeValue && i < data.length) { negativeValue = data[i++] < 0; } return negativeValue; }
Kod wygląda na bardziej szczegółowy i zrozumiały. Możesz nawet utworzyć tablicę w wywołaniu metody, na przykład:
checkIfAnyNegative(new DataType[] { defaultStock, defaultWholesale, defaultRetail, defaultDelivery });
Jest bardziej czytelny niż „ciąg porównawczy”, a także ma przewagę wydajności w postaci zwarcia (kosztem alokacji tablicy i wywołania metody).
Edycja: Jeszcze większą czytelność można po prostu osiągnąć za pomocą parametrów varargs:
Podpis metody wyglądałby następująco:
boolean checkIfAnyNegative(DataType ... data)
A wezwanie mogłoby wyglądać tak:
źródło
To stary post, ale aby przedstawić inną perspektywę początkującym, chciałbym podać przykład.
Myślę, że najczęstszym przypadkiem użycia dla podobnego operatora złożonego byłoby
+=
. Jestem pewien, że wszyscy napisaliśmy coś takiego:int a = 10; // a = 10 a += 5; // a = 15
Jaki był tego cel? Chodziło o uniknięcie schematu i wyeliminowanie powtarzającego się kodu.
Tak więc następna linia robi dokładnie to samo, unikając wpisywania zmiennej
b1
dwa razy w tym samym wierszu.źródło
longNameOfAccumulatorAVariable += 5;
kontralongNameOfAccumulatorAVariable = longNameOfAccumulatorVVariable + 5;
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, defaultRetail, defaultDelivery); int minParam = Collections.min (params); negativeValue = minParam < 0;
źródło
negativeValue = defaultStock < 0 || defaultWholesale < 0
itd. Pomijając nieefektywność całego pakowania i pakowania, które tu się dzieje, nie jest mi tak łatwo zrozumieć, co naprawdę oznaczałby twój kod.|| logiczne boolowskie OR
| bitowe OR
| = bitowe operator OR i przypisanie
Powodem, dla którego | = nie shortcircit jest to, że wykonuje bitowe OR, a nie logiczne OR. To jest do powiedzenia:
Samouczek dla operatorów Java
źródło
|
jest liczbą całkowitą bitową OR, ale jest też logicznym OR - zobacz specyfikację języka Java 15.22.2.