Czy dobrą praktyką jest używanie operatora xor do sprawdzania wartości logicznych? [Zamknięte]


150

Ja osobiście jak wyłącznego lub , ^, operatora, gdy ma to sens w kontekście logicznych kontroli ze względu na jego zwięzłość. Wolę pisać

if (boolean1 ^ boolean2)
{
  //do it
}

niż

if((boolean1 && !boolean2) || (boolean2 && !boolean1))
{
  //do it
}

ale często mam zdezorientowane spojrzenia od innych doświadczonych programistów Java (nie tylko początkujących), a czasami komentarze o tym, jak powinno być używane tylko do operacji bitowych.

Ciekawi mnie najlepsze praktyki dotyczące korzystania z ^operatora.

Odpowiedzi:


298

Możesz po prostu użyć !=zamiast tego.


36
„Co jest nie tak z! =” bool1 ^ bool2 ^ bool3bool1 != bool2 != bool3
Ma

4
Mój mózg boli. Czy zatem! = Daje nieprawidłowe wyniki, czy nie?
vemv

27
@vemv, !=zwraca poprawne wyniki dla booleans (ale nie dla Booleans, więc bądź ostrożny). Jednak nie zawsze jest ładny, na przykład (some != null) != (other != null)nie jest zbyt czytelny. Musisz albo wyodrębnić części w jawnych wartościach logicznych, albo !=w oddzielnej metodzie.
ivant

23
Oto dlaczego: a ^ b=> "a lub b, ale nie oba", a != b=> "a nie jest równe b". (Co powiedział @RobertGrant). Większość ludzi zrozumiałaby pierwszy z nich łatwiej, gdyby wiedzieli, czym jest xor (co jest bardzo przydatne, jeśli jesteś w branży komputerowej ...)
Harold R. Eason

2
@ HaroldR.Eason ważny czepianie się tutaj: a != b=> "a nie jest IDENTYCZNE dla b"
Mario Reutter

27

Myślę, że odpowiedziałeś na swoje własne pytanie - jeśli ludzie dziwią ci się, bezpieczniej jest wybrać bardziej wyraźną opcję.

Jeśli chcesz to skomentować, prawdopodobnie lepiej zastąp go bardziej szczegółową wersją i nie zmuszaj ludzi do zadawania pytań w pierwszej kolejności.


6
Mogę cię zapewnić, będziesz miał dziwne spojrzenia ode mnie, kiedy poważnie napiszesz (boolean1 && !boolean2) || (boolean2 && !boolean1)w prawdziwym kodzie aplikacji…
Holger

17

Uważam, że często prowadzę podobne rozmowy. Z jednej strony masz kompaktową, skuteczną metodę osiągnięcia celu. Z drugiej strony masz coś, czego reszta twojego zespołu może nie zrozumieć, co utrudnia utrzymanie tego w przyszłości.

Moją ogólną zasadą jest pytanie, czy używana technika jest czymś, czego można oczekiwać od programistów w ogóle. W tym przypadku myślę, że rozsądne jest oczekiwanie, że programiści będą wiedzieli, jak używać operatorów boolowskich, więc użycie xor w instrukcji if jest w porządku.

Jako przykład czegoś, co nie byłoby w porządku, weź sztuczkę polegającą na użyciu xor do zamiany dwóch zmiennych bez użycia zmiennej tymczasowej. To sztuczka, której nie spodziewałbym się, że wszyscy się znają, więc nie przejdzie weryfikacji kodu.


14

Myślę, że byłoby dobrze, gdybyś to skomentował, np // ^ == XOR.


10

Zawsze możesz po prostu zawinąć go w funkcję, aby nadać jej pełną nazwę:

public static boolean XOR(boolean A, boolean B) {
    return A ^ B;
}

Ale wydaje mi się, że nie byłoby to trudne dla każdego, kto nie wiedział, do czego służy operator ^, aby Google to naprawdę szybko. Nie będzie trudno to przypomnieć sobie po raz pierwszy. Ponieważ poprosiłeś o inne zastosowania, często używa się XOR do maskowania bitów.

Możesz także użyć XOR, aby zamienić wartości w dwóch zmiennych bez używania trzeciej zmiennej tymczasowej .

// Swap the values in A and B
A ^= B;
B ^= A;
A ^= B;

Oto pytanie Stackoverflow związane z zamianą XOR .


6

Niedawno użyłem xora w projekcie JavaScript w pracy i ostatecznie dodałem 7 wierszy komentarzy, aby wyjaśnić, co się dzieje. Uzasadnienie zastosowania XOR w tym kontekście to, że jedno z określeń ( term1w poniższym przykładzie) może przyjmować nie tylko dwa z trzech wartości: undefined, truelub falsegdy inne ( term2) może być truelub false. Musiałbym dodać dodatkowe sprawdzenie dla undefinedprzypadków, ale z xor wystarczyło, ponieważ xor wymusza na pierwszym członie, aby był oceniany jako wartość logiczna, pozwalając na undefinedtraktowanie go jako false:

if (term1 ^ term2) { ...

Ostatecznie było to trochę przesada, ale i tak chciałem to tam zatrzymać, jako rodzaj pisanki.


IMHO, zamiast polegać na niejawnej konwersji, w sytuacji, która jest niezwykła, lepiej jest uczynić konwersję jawną . Ogólnie rzecz biorąc, „pozwolenie, by niezdefiniowane traktowano jako fałszywe” jest wątpliwą praktyką w każdym języku. Nie korzystałem z wartości trójstanowych w Javie, ale w C # bool? awartość można jawnie przetestować pod kątem prawdziwego użycia a == true- czy istnieje podobna technika w Javie? W C #, biorąc pod uwagę dwie bool?wartości, „traktuj null jako fałsz” prowadzi do (a == true) ^ (b == true). Równoważna formuła to (a == true) != (b == true). Czy możesz zrobić coś podobnego w Javie?
ToolmakerSteve

5
if((boolean1 && !boolean2) || (boolean2 && !boolean1)) 
{ 
  //do it 
} 

IMHO ten kod można uprościć:

if(boolean1 != boolean2) 
{ 
  //do it 
} 

5

Mając na uwadze przejrzystość kodu, uważam, że używanie XOR w sprawdzeniach boolowskich nie jest typowym zastosowaniem operatora bitowego XOR. Z mojego doświadczenia wynika, że ​​bitowe XOR w Javie jest zwykle używane do implementacji flag togglezachowania maski :

flags = flags ^ MASK;

Ten artykuł autorstwa Vipan Singla wyjaśnia bardziej szczegółowo przypadek użycia.

Jeśli chcesz użyć bitowego XOR, jak w swoim przykładzie, skomentuj, dlaczego go używasz, ponieważ prawdopodobnie nawet bitowa literatura będzie wymagać zatrzymania się na ścieżce, aby zrozumieć, dlaczego go używasz.


-1

Osobiście wolę wyrażenie „boolean1 ^ boolean2” ze względu na jego zwięzłość.

Gdybym był w Twojej sytuacji (pracując w zespole), poszedłbym na kompromis, umieszczając logikę „boolean1 ^ boolean2” w funkcji o nazwie opisowej, takiej jak „isDifferent (boolean1, boolean2)”.

Na przykład zamiast używać „boolean1 ^ boolean2”, możesz wywołać „isDifferent (boolean1, boolean2)” w ten sposób:

if (isDifferent(boolean1, boolean2))
{
  //do it
}

Twoja funkcja „isDifferent (boolean1, boolean2)” wyglądałaby następująco:

private boolean isDifferent(boolean1, boolean2)
{
    return boolean1 ^ boolean2;
}

Oczywiście to rozwiązanie pociąga za sobą użycie pozornie obcego wywołania funkcji, które samo w sobie podlega kontroli Najlepszych praktyk, ale pozwala uniknąć rozwlekłego (i brzydkiego) wyrażenia „(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) „!


-2

Jeśli wzorzec użycia to uzasadnia, dlaczego nie? Podczas gdy Twój zespół nie rozpoznaje operatora od razu, z czasem mogliby to zrobić. Ludzie cały czas uczą się nowych słów. Dlaczego nie w programowaniu?

Jedyne ostrzeżenie, jakie mogę powiedzieć, to to, że "^" nie ma semantyki zwarcia z twojego drugiego testu boolowskiego. Jeśli naprawdę potrzebujesz semantyki zwarć, to działa również statyczna metoda util.

public static boolean xor(boolean a, boolean b) {
    return (a && !b) || (b && !a);
}

16
Nie widzę możliwego zwarcia z xor - musisz znać oba a i b, aby ocenić wynik.
Thelema

7
Ponadto argumenty byłyby oceniane w czasie połączenia, więc żadne zwarcie nie nastąpi.
erikkallen

3
Dodatkowo xor powinien być pojedynczą operacją na poziomie maszyny.
Ogre Psalm 33

Prawdopodobnie powinieneś sprawdzić różnicę między oceną zwarcia a oceną leniwą. Ocena zwarciowa to styl kodu, który zapobiega wywołaniom, które w przeciwnym razie spowodowałyby błędy w czasie wykonywania, takie jak dzielenie przez zero. W C może to być ´if (mianownik! = 0 && licznik / mianownik) ´, co w tym przypadku wykorzystuje leniwą ocenę, aby zapobiec dzieleniu przez zero. Twoja odpowiedź jest również czysto spekulacyjna.
Martin

2
Szczerze mówiąc, programista piszący funkcję xor, która robi dokładnie to, co robi operator xor, ale w okrężny sposób, wywołałby w moim umyśle więcej pytań (szczególnie dotyczących kompetencji) niż programista, który właśnie użył ^.
Stijn de Witt

-3

! = jest OK, aby porównać dwie zmienne. Nie działa to jednak w przypadku wielokrotnych porównań.


-3

Jako operator bitowy, xor jest znacznie szybszy niż jakikolwiek inny sposób, aby go zastąpić. Dlatego w przypadku obliczeń krytycznych dla wydajności i skalowalnych obliczeń xor jest niezbędny.

Moja subiektywna osobista opinia: absolutnie zabronione jest, w jakimkolwiek celu, używanie równości (== lub! =) Dla wartości logicznych. Używanie go wskazuje na brak podstawowej etyki i podstaw programowania. Każdy, kto patrzy na Ciebie ze zdezorientowaniem ^, powinien zostać odesłany z powrotem do podstaw algebry Boole'a (kusiło mnie, aby napisać tutaj „do rzek wiary” :)).


1
Tyle tylko, że JIT jest wyjątkowo dobry w (małych) optymalizacjach typu dziurka od klucza, takich jak zastępowanie jednego wyrażenia boolowskiego innym.
David Leppik,

1
Ponadto ^ nie jest głównie operatorem boolowskim (logicznym), jest operatorem bitowym. Mówi czytelnikowi, aby zwolnił, ponieważ prawdopodobnie wystąpią błędy w znakach. Jeśli użyjesz ^ for! =, Będziesz naprawdę zepsuty, jeśli kiedykolwiek będziesz programować w C. Operatory bitowe są sygnałem dla twoich czytelników (tych, którzy debugują twój kod, w tym ciebie), aby zwolnić i szukać błędów ze znakami . I mogą być trudne. Na przykład, czy wiesz, że% w Javie nie jest prawdziwym modulo, jak w C lub Pythonie? Miałem kiedyś fragment kodu, który działał tak samo w C, JavaScript i Pythonie, ale nie w Javie.
David Leppik,

6
Jak to się kiedykolwiek zyskało? Po pierwsze, w Javie kompilowane są XOR i! = [ Stackoverflow.com/a/4175512/202504] ( dokładnie ten sam kod), po drugie nawet w asemblerze testującym pod kątem równości, a xor to pojedyncze proste operacje. Czy masz jakieś liczby na poparcie swojego wyciągu?
jmiserez

-4
str.contains("!=") ^ str.startsWith("not(")

wygląda dla mnie lepiej niż

str.contains("!=") != str.startsWith("not(")
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.