Чи є хорошою практикою використовувати оператор xor для булевих перевірок? [зачинено]


150

Мені особисто подобається ексклюзивний або , ^оператор, коли це має сенс у контексті булевих перевірок через його стислість. Я дуже вважаю за краще писати

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

ніж

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

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

Мені цікаво про кращі практики щодо використання ^оператора.

Відповіді:


298

Ви можете просто використовувати !=замість цього.


36
"Що з цим! =" bool1 ^ bool2 ^ bool3bool1 != bool2 != bool3
Має

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=> "a не ІДЕНТИЧНО для b"
Mario Reutter

27

Я думаю, що ти відповів на власне запитання - якщо ти отримуєш дивні погляди від людей, напевно, безпечніше йти з більш чітким варіантом.

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


6
Я можу стверджувати, що ви отримаєте дивні погляди від мене, коли ви серйозно (boolean1 && !boolean2) || (boolean2 && !boolean1)
Holger

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?значень, "трактувати null як хибне" призведе до (a == true) ^ (b == true). Еквівалентна формула (a == true) != (b == true). Ви можете зробити щось подібне в java?
ToolmakerSteve

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

IMHO цей код можна спростити:

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;
}

Звичайно, це рішення тягне за собою використання нібито стороннього виклику функції, який сам по собі підлягає уважному огляду кращих практик, але він уникає багатослівного (і потворного) виразу "(boolean1 &&! Boolean2) || (boolean2 &&! Boolean1) "!


-2

Якщо схема використання це виправдовує, чому б ні? Поки ваша команда не розпізнає оператора одразу, з часом. Люди весь час навчаються нових слів. Чому б не в програмуванні?

Єдине застереження, яке я можу зазначити, - це те, що "^" не має семантики короткого замикання вашої другої булевої перевірки. Якщо вам дуже потрібна семантика короткого замикання, то і статичний метод утиліти теж працює.

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

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

7
Крім того, аргументи будуть оцінені під час виклику, тому жодного короткого замикання не відбудеться.
erikkallen

3
Крім того, xor має бути однією операцією на рівні машини.
Псалом Огре3333

Вам, мабуть, слід шукати різницю між оцінкою короткого замикання та лінивою оцінкою. Коротке оцінювання - це стиль коду, який запобігає викликам, які в іншому випадку можуть призвести до помилок виконання, наприклад поділу на нуль. У C це може бути "if (знаменник! = 0 && чисельник / знаменник)", який в ньому самостійно використовує ледачу оцінку для запобігання поділу на нуль. Ваша відповідь також суто спекулятивна.
Мартін

2
Якщо чесно, програміст, який пише функцію xor, робить саме те, що робить оператор xor, але в обхідному напрямку, викликає у мене більше запитань (зокрема, щодо компетенції), ніж програміст, який щойно використовувався ^.
Штійн де Вітт

-3

! = це нормально для порівняння двох змінних. Однак це не працює при кількох порівняннях.


-3

Як бітовий оператор, xor набагато швидше, ніж будь-який інший спосіб його заміни. Отже, для критичних та масштабованих розрахунків щодо ефективності, xor є обов'язковим.

Моя суб'єктивна особиста думка: абсолютно заборонено з будь-якою метою використовувати рівність (== або! =) Для булів. Використання його свідчить про відсутність базової етики та основ програмування. Кожен, хто розгублено переглядає ^, повинен повернутись до основ булевої алгебри (я спокусився написати "до річок віри" тут :)).


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

1
Крім того, ^ - це не передусім булівський (логічний) оператор, це побітовий оператор. Це підказує читачеві гальмувати, тому що, ймовірно, є помилки знаків. Якщо ви використовуєте ^ for! =, Ви дійсно заблудитеся, якщо коли-небудь програмуєте на 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.