Відмінності булевих операторів: & vs && і | проти ||


Відповіді:


134

Це оператори побітового AND і бітового АБО.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

Дякуємо Карлосу за те, що він вказав відповідний розділ у специфікації мови Java ( 15.22.1 , 15.22.2 ) щодо різних поведінок оператора на основі його входів.

Дійсно, коли обидва входи булеві, оператори вважаються логічними операторами Loolean і поводяться аналогічно операторам Conditional-And ( &&) та Conditional-Or ( ||), за винятком того, що вони не мають короткого замикання. :

if((a != null) && (a.something == 3)){
}

Це не:

if((a != null) & (a.something == 3)){
}

"Коротке замикання" означає, що оператор не обов'язково вивчає всі умови. У наведених вище прикладах &&буде вивчено другу умову лише тоді, коли aїї немає null(інакше вся заявка повернеться помилковою, і все одно було б вивчити наступні умови), тому заява a.somethingне спричинить виняток або вважається "безпечною" . "

&Оператор завжди розглядає всі умови в реченні, так і в наведених вище прикладах, a.somethingможе бути оцінений , коли aнасправді nullзначення, викликаючи виняток.


1
хотів уточнити .. & поверне 1, лише якщо БОТИ 1? Так 101 & 001 було б 001? Правильно?
gideon

@giddy @Jonathon - я оновив свої значення, щоб краще показати цю ситуацію.
Джастін Ніссснер

неповні: вони також є ЛОГІЧНИми операторами (для булів).
користувач85421

1
@ Карлос - Ні. Вони все ще побитові оператори. Вони просто поводяться так само, як логічні оператори, що не мають короткого замикання. Є різниця.
Джастін Нісснер

4
і що таке логічні оператори, що не мають короткого замикання? Оператори & та | (запитує ОП) - це "Цільові побітові оператори" (JLS 15.22.1) та "Логічні логічні оператори" (JLS 15.22.2). Або в цьому неправильна специфікація мови Java?
користувач85421

108

Я думаю, ви говорите про логічне значення обох операторів, тут у вас є таблиця-резюме:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

Оцінка короткого замикання , мінімальна оцінка або оцінка Маккарті (після Джона Маккарті) - це семантика деяких булевих операторів у деяких мовах програмування, в яких другий аргумент виконується або оцінюється лише в тому випадку, якщо першого аргументу недостатньо для визначення значення вираз: коли перший аргумент функції AND оцінюється як false, загальне значення повинно бути помилковим; і коли перший аргумент функції АБО оцінюється як істинне, загальне значення повинно бути істинним.

Не безпечно означає, що оператор завжди вивчає кожну умову в пункті, тому в наведених вище прикладах 1 / x може бути оцінена, коли значення x є, по суті, значенням 0, викликаючи виняток.


1
@Torres - розкладіть відповідь, пояснивши "коротке замикання" та "безпечно". Також "ексклюзив" чи "логічний не" також "не короткий замикання"? І чому його називають «логічним не», а не «булевим логічним не»? І чому "логічний НЕ" не групується з "логічним І" та "логічним АБО"? Гарна відповідь, але потрібна робота.
tfmontague

@tfmontague, я пояснив, що означає коротке замикання (редагуючи цю відповідь). Чекаю, коли моя редакція буде "перевірена".
Таслім Осені

що "небезпечно" в тому, щоб не було короткого замикання? чи не повинно бути безпечніше, ніж використання короткого замикання? btw: ви дійсно не пояснюєте термін "короткого замикання". це означає, що на "не коротке замикання" спочатку оцінюються всі частини, потім застосовується булева операція, тоді як на короткому замиканні оцінка припиняється, коли перший вираз задовольняє умові, наприклад (a || b) не буде оцініть b, якщо a є правдою і операція поверне істину, незалежно від того, що це b.
SCI

26

Я знаю, що тут багато відповідей, але всі вони здаються дещо заплутаними. Отож, провівши деякі дослідження з навчального посібника Java oracle, я придумав три різні сценарії використання && або &. Три сценарії є логічним AND , розрядним AND і булевим AND .

Логічний І: Логічний І (він же умовний І) використовує оператор && . Це значення короткого замикання: якщо лівий операнд хибний, правий операнд не буде оцінений.
Приклад:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

У наведеному вище прикладі значення, надруковане на консолі x, буде дорівнює 0, оскільки перший операнд у операторі if хибний, тому java не потребує обчислення (1 == ++ x), тому x не обчислюється.

Побітові І: Побітові І використовує оператор & . Він використовується для попередньої попередньої операції зі значенням. Набагато простіше зрозуміти, що відбувається, переглянувши операцію на двійкових числах, наприклад:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

Як ви бачите в прикладі, коли бінарні подання чисел 5 і 12 вишикуються, то побітові І попередньо формовані будуть створювати лише двійкове число, де однакові цифри в обох числах мають 1. Отже, 0101 & 1100 == 0100. Який у десятковій формі дорівнює 5 & 12 == 4.

Булевий І: Тепер оператор булевого І поводиться так само і по-різному, як по бітовому І та логічному І. Мені подобається думати про це як попереднє формування бітового І між двома булевими значеннями (або бітами), тому він використовує & operator. Булеві значення також можуть бути результатом логічного виразу.

Він повертає або істинне, або хибне значення, подібно до логічного AND, але на відміну від логічного AND не є короткозамкненим. Причина полягає в тому, що для того, щоб виконати цю побітну операцію AND, вона повинна знати значення як лівого, так і правого операндів. Ось колишній:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

Тепер, коли це запускається, вираз (1 == ++ x) буде виконаний, навіть якщо лівий операнд хибний. Значить, значення, надруковане для x, буде дорівнює 1, оскільки воно збільшується.

Це також стосується логічного АБО (||), порозрядного АБО (|) та булевого АБО (|). Сподіваюсь, це усуне певну плутанину.


to preform that bitwise AND, it must know the value of both left and right operandsЦе мені не здається правильним. Для виконання a BITWISE ANDвам не потрібно знати правий операнд, щоб мати можливість з'ясувати результат, якщо лівий операнд FALSE. Те, що ви пояснюєте, є правильним, але міркування, які ви заявляєте, не здаються мені такими, щонайменше ..
Корай Тугай

7

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


7
-1 за те, що сказав ОП те, що він уже знав, і не відповів на запитання, яке він насправді задав.
Альнітак

5

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


1
Неправильно .... Бо &&він оцінює обидва результати, а ||повертається лише у тому випадку, якщо перша умова є вірною.
Buhake Sindi

1
Так? && оцінює лише праву частину виразу, якщо ліва частина вже оцінює істинну. В іншому випадку він перестає оцінюватись як перший помилковий підтекст, означає, що результат не може бути правдивим. Дивіться jguru.com/faq/view.jsp?EID=16530
Брайан Скотт,

1
( 2 & 4 )оцінює до false, тоді як ( 2 && 4 )оцінює до true. Як саме такий результат?
Пісквор покинув будівлю

1
@Piskvor - не на Java! 2 & 4призводить до цілого числа, а не булевого (нуль у цьому випадку). 2 && 4не компілюватиметься, && приймає лише булеві. Java не дозволяє змішувати булеві і ints: нуль не false, falseне нуль ...
user85421

1
@BuhakeSindi Неправильно. Бо &&він оцінює другий операнд лише у тому випадку, коли є перший операнд true.
Маркіз Лорн

2

У Java єдині оператори &, |, ^,! залежать від операндів. Якщо обидва операнди є ints, то виконується побітова операція. Якщо обидва булеві, виконується "логічна" операція.

Якщо невідповідність обох операндів, викидається помилка часу компіляції.

Подвійні оператори &&, || поводяться аналогічно своїм одиночним аналогам, але обидва операнди повинні бути умовними виразами, наприклад:

якщо ((a <0) && (b <0)) {...} або аналогічно, якщо ((a <0) || (b <0)) {...}

джерело: янг програмування янг 4-е вид



1

Можливо, може бути корисним знати, що побітові оператори AND і побітові ІЛО завжди оцінюються перед умовними AND і умовними АБО, що використовуються в одному виразі.

if ( (1>2) && (2>1) | true) // false!

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

1

&&; || є логічними операторами .... коротке замикання

&; | булеві логічні оператори .... Некоротке замикання

Перехід до відмінностей у виконанні на виразах. Побітні оператори оцінюють обидві сторони незалежно від результату лівої частини. Але у випадку оцінки виразів з логічними операторами оцінка виразу правої руки залежить від стану лівої руки.

Наприклад:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Це надрукує i = 26; j = 25, Оскільки перша умова помилкова, стан правої руки обходить, оскільки результат є помилковим у будь-якому випадку незалежно від стану правої руки (коротке замикання)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

Але, це надрукує i = 26; j = 26,


0

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

Коли виражається оператор && , оцінюється перший операнд. Якщо перший операнд оцінюється як хибний, оцінка другого операнда пропускається.

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

Подібні для | та ||


0

У той час як основна відмінність полягає в тому , що &використовується для бітових операцій в основному на long, intабо byteде він може бути використаний для виду маски, результати можуть відрізнятися , навіть якщо використовувати його замість логічного &&.

Різниця помітніша в деяких сценаріях:

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

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

Для другої точки дивіться цей приклад:

if ((a != null) & (a.isEmpty()))

Це не вдається null, оскільки оцінка другого виразу виробляє a NullPointerException. Логічний оператор &&лінивий, якщо лівий операнд хибний, результат помилковий, незалежно від того, який правий операнд.

Приклад третього моменту - скажімо, у нас є додаток, який використовує БД без жодних тригерів чи каскадів. Перш ніж видалити об'єкт Building, ми повинні змінити будівлю об'єкта Department на іншу. Скажімо також, що стан операції повертається як булева (true = успіх). Тоді:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

Це оцінює обидва вирази і, таким чином, виконує видалення будівлі, навіть якщо оновлення відділу з якоїсь причини не вдалося. З&& , він працює за призначенням і зупиняється після першої відмови.

Щодо того a || b, він еквівалентний !(!a && !b), він припиняється, якщо aце правда, більше пояснень не потрібно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.