Является ли хорошей практикой использование оператора xor для логических проверок? [закрыто]


150

Я лично , как исключающие или , ^, оператор , когда это имеет смысл в контексте логических проверок из - за свою лаконичность. Я предпочитаю писать

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

чем

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

но меня часто смущают взгляды других опытных разработчиков Java (не только новичков), а иногда и комментарии о том, как его следует использовать только для побитовых операций.

Мне любопытно, что касается лучших практик использования ^оператора.

Ответы:


298

Вы можете просто использовать !=вместо этого.


36
«Что не так! =» bool1 ^ bool2 ^ bool3 Имеет для меня более логичный смысл, чемbool1 != bool2 != bool3
BlueRaja - Дэнни Пфлюгофт

4
Мой мозг болит. Так может! = Давать неверные результаты или нет?
VEMV

27
@vemv, !=дает правильные результаты для booleans (но не для Booleans, поэтому будьте осторожны). Это не всегда красиво, например (some != null) != (other != null), не очень читабельно. Вы должны либо извлечь части в явных логических значениях, либо извлечь !=их отдельным методом.
ivant

23
Вот почему: a ^ b=> "a или b, но не оба", a != b=> "a не равно b". (Что сказал @RobertGrant). Большинству людей было бы легче понять первое, если бы они знали, что такое xor (что очень полезно знать, если вы работаете в области вычислительной техники ...)
Гарольд Р. Исон

2
@ HaroldR.Eason важно придираться здесь: a != b=> «а не является ИДЕНТИЧНЫМ для б»
Марио Ройтер

27

Я думаю, что вы ответили на свой собственный вопрос - если вы получаете странные взгляды от людей, возможно, безопаснее пойти с более явным вариантом.

Если вам нужно это прокомментировать, то вам, вероятно, лучше заменить его более подробной версией и не заставлять людей задавать вопрос в первую очередь.


6
Я могу вас утверждать, вы получите странные взгляды от меня, когда вы серьезно напишите (boolean1 && !boolean2) || (boolean2 && !boolean1)в реальном коде приложения ...
Хольгер

17

Я нахожу, что у меня много подобных разговоров. С одной стороны, у вас есть компактный, эффективный метод достижения вашей цели. С другой стороны, у вас есть кое-что, что остальная часть вашей команды может не понять, что затруднит его сохранение в будущем.

Мое общее правило - спрашивать, является ли используемая методика разумной для программистов. В этом случае я думаю, что разумно ожидать, что программисты будут знать, как использовать логические операторы, поэтому использование xor в операторе if - это нормально.

В качестве примера чего-то, что не было бы хорошо, возьмите хитрость использования xor для замены двух переменных без использования временной переменной. Это хитрость, с которой я не ожидал бы, что все будут знакомы, поэтому она не прошла бы проверку кода.


14

Я думаю, что было бы хорошо, если бы вы это прокомментировали, например // ^ == XOR.


10

Вы всегда можете просто обернуть его в функцию, чтобы дать ему подробное имя:

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

Но мне кажется, что для любого, кто не знал, что оператор ^ для Google, это было бы не сложно, это действительно быстро. Это не будет трудно вспомнить после первого раза. Поскольку вы запрашивали другие варианты использования, для использования битовой маскировки обычно используется XOR.

Вы также можете использовать XOR для замены значений в двух переменных без использования третьей временной переменной .

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

Вот вопрос Stackoverflow, связанный с заменой XOR .


6

Недавно я использовал xor в проекте JavaScript на работе и добавил 7 строк комментариев, чтобы объяснить, что происходит. Обоснование использования XOR в этом контексте было то , что одним из условий ( term1в приведенном ниже примере) может взять на себя не два , а три значения: undefined, trueили в falseто время как другие ( term2) может быть trueили false. Я должен был бы добавить дополнительную проверку для undefinedслучаев, но с xor, следующего было достаточно, поскольку xor заставляет первый член сначала быть оценен как логическое значение, позволяя undefinedобрабатываться как false:

if (term1 ^ term2) { ...

В конце концов, это было немного излишним, но я все равно хотел оставить его там, как пасхальное яйцо.


ИМХО, вместо того, чтобы полагаться на неявное преобразование, в ситуации, с которой приходится сталкиваться, лучше сделать преобразование явным . И вообще, «позволить неопределённому лечиться как ложному» - сомнительная практика на любом языке. Я не использовал значения трех состояний в Java, но в C # bool? aзначение может быть явно проверено на истинное использование a == true- есть ли подобный метод в Java? В C #, учитывая два bool?значения, «обрабатывать ноль как ложь» приведет к (a == true) ^ (b == true). Эквивалентная формула (a == true) != (b == true). Можете ли вы сделать что-то подобное в Java?
ToolmakerSteve

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

ИМХО этот код можно упростить:

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

5

Учитывая ясность кода, я считаю, что использование XOR в логических проверках не является типичным использованием побитового оператора XOR. Из моего опыта побитовый XOR в Java обычно используется для реализации flag toggleповедения маски :

flags = flags ^ MASK;

Эта статья Випана Сингла объясняет случай использования более подробно.

Если вам нужно использовать побитовый XOR, как в вашем примере, прокомментируйте, почему вы его используете, поскольку, вероятно, потребуется даже побитовая грамотная аудитория, чтобы остановиться, чтобы понять, почему вы ее используете.


-1

Я лично предпочитаю выражение "boolean1 ^ boolean2" из-за его краткости.

Если бы я был в вашей ситуации (работая в команде), я бы пошел на компромисс, заключив логику «boolean1 ^ boolean2» в функцию с описательным именем, таким как «isDifferent (boolean1, boolean2)».

Например, вместо использования «boolean1 ^ boolean2», вы бы назвали «isDifferent (boolean1, boolean2)» следующим образом:

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

Ваша функция isDifferent (boolean1, boolean2) будет выглядеть так:

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

Конечно, это решение влечет за собой использование якобы постороннего вызова функции, который сам по себе подлежит проверке Best Practices, но он избегает многословного (и уродливого) выражения "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) «!


-2

Если модель использования оправдывает это, почему бы и нет? Хотя ваша команда не сразу узнает оператора, со временем они могут. Люди постоянно учат новые слова. Почему не в программировании?

Единственное предостережение, которое я могу заявить, это то, что у «^» нет семантики короткого замыкания вашей второй логической проверки. Если вам действительно нужна семантика короткого замыкания, тогда работает статический метод util.

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

16
Я не вижу возможности короткого замыкания с xor - вы должны знать и a, и b, чтобы оценить результат.
Телема

7
Кроме того, аргументы будут оцениваться во время вызова, поэтому никакого короткого замыкания не произойдет.
erikkallen

3
Кроме того, xor должна быть единственной операцией на уровне машины.
Огр псалом 33

Вероятно, вам следует поискать разницу между оценкой короткого замыкания и отложенной оценкой. Оценка короткого замыкания - это стиль кода, который предотвращает вызовы, которые в противном случае могли бы привести к ошибкам во время выполнения, таким как деление на ноль. В C это может быть «if (знаменатель! = 0 && числитель / знаменатель)», что само по себе использует ленивую оценку для предотвращения деления на ноль. Ваш ответ тоже чисто умозрительный.
Мартин

2
Если честно, программист, пишущий функцию xor, которая делает именно то, что делает оператор xor, но окольным путем, вызовет у меня больше вопросов (особенно о компетенции), чем программист, который только что использовал ^.
Стейн де Витт

-3

! = можно сравнить две переменные. Это не работает, однако, с несколькими сравнениями.


-3

Как побитовый оператор, xor намного быстрее, чем любой другой способ его замены. Поэтому для критичных к производительности и масштабируемых вычислений xor является обязательным условием.

Мое субъективное личное мнение: категорически запрещается использовать равенство (== или! =) Для логических значений. Его использование показывает отсутствие базовой этики и основ программирования. Любой, кто дает вам запутанные взгляды на ^, должен быть возвращен к основам булевой алгебры (у меня было искушение написать «рекам веры» здесь :)).


1
За исключением того, что JIT чрезвычайно хорош в оптимизации (замкнутых скважин), таких как замена одного логического выражения другим.
Дэвид Леппик

1
Кроме того, ^ - это не булевский (логический) оператор, это побитовый оператор. Это говорит читателю, чтобы замедлиться, потому что могут быть ошибки знака. Если вы используете ^ для! =, Вы действительно запутаетесь, если будете когда-либо программировать на C. Битовые операторы - это сигнал для ваших читателей (тех, кто отлаживает ваш код, включая вас), чтобы замедлиться и искать ошибки знака , И они могут быть хитрыми. Например, знаете ли вы, что Java% не является истинным по модулю, как в C или Python? Когда-то у меня был фрагмент кода, который работал одинаково в C, JavaScript и Python, но не в Java.
Дэвид Леппик

6
Как за это проголосовали? Во-первых, в Java скомпилированы XOR и! = [ Stackoverflow.com/a/4175512/202504]( в точно такой же код), во-вторых, даже в ассемблерном тестировании на равенство и xor - это отдельные простые операции. У вас есть какие-либо цифры для подтверждения вашего заявления?
jmiserez

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

выглядит лучше для меня, чем

str.contains("!=") != str.startsWith("not(")
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.