Рекомендуется ли использовать оператор xor для булевых проверок?

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

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

чем

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

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

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

13 ответов


вы можете просто использовать .


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

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


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

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

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


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


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

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.


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

if (term1 ^ term2) { ...

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

flags = flags ^ MASK;

этой статья Vipan Singla объясняет случай использования более подробно.

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


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

IMHO этот код может быть упрощен:

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

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

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

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

Я лично предпочитаю выражение "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;
}

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


!= можно сравнить две переменные. Однако это не работает при множественных сравнениях.


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

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

str.contains("!=") != str.startsWith("not(")

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

мое субъективное личное мнение: абсолютно запрещено, для каких-либо целей, использовать равенство (== или != ) для логических значений. Использование его показывает отсутствие базовой этики программирования и основ. Любой, кто дает вам смущенные взгляды, должен быть отправлен обратно к основам булевой алгебры (у меня было искушение написать " к рекам веры" здесь :) ).