Інші відповіді вдало вирішили розкрити функціональну різницю між операторами, але відповіді можуть стосуватися майже кожної окремо взятої мови С, яка існує сьогодні. Питання позначено тегомjava, і тому я постараюся відповісти спеціально та технічно на мові Java.
&і |можуть бути або операторами побітових розрядів, або булевими логічними операторами. Синтаксис бітових та логічних операторів ( §15.22 ):
AndExpression:
EqualityExpression
AndExpression & EqualityExpression
ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression ^ AndExpression
InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression | ExclusiveOrExpression
Синтаксис для EqualityExpressionвизначений у § 15.21 , що вимагає RelationalExpressionвизначення у § 15.20 , що, у свою чергу, вимагає ShiftExpressionта ReferenceTypeвизначено відповідно у § 15.19 та §4.3 . ShiftExpressionвимагає AdditiveExpressionвизначеного в § 15.18 , який продовжує свердлити, визначаючи основні арифметичні, одинарні оператори тощо ReferenceType. (Хоча ReferenceTypeне включає примітивні типи, в остаточному підсумку визначається визначення примітивних типів, оскільки вони можуть бути типом виміру для масиву, який є a ReferenceType.)
Бітові та логічні оператори мають такі властивості:
- Ці оператори мають різний пріоритет,
&мають найвищий пріоритет і |найнижчий пріоритет.
- Кожен з цих операторів є синтаксично ліво-асоціативним (кожна група зліва направо).
- Кожен оператор є комутативним, якщо вирази операнда не мають побічних ефектів.
- Кожен оператор асоціативний.
- Побітові та логічні оператори можуть використовуватися для порівняння двох операндів числового типу або двох операндів типу
boolean. Усі інші випадки призводять до помилки часу компіляції.
Відмінність того, чи оператор виконує функцію побітового або логічного оператора, залежить від того, "операнди" конвертовані в примітивний інтегральний тип "( §4.2 ) або вони мають типи booleanабо Boolean( §5.1.8 ).
Якщо операнди є інтегральними типами, на обох операндах виконується двійкове числове просування ( §5.6.2 ), залишаючи їх як longs, так і ints для операції. Тип операції буде типом (просунутих) операндів. У цей момент &буде розрядне І, ^буде побітним винятком АБО, і |буде побітовим включенням АБО. ( §15.22.1 )
Якщо операнди є, booleanабо Booleanоперанди будуть підлягати конвертації розпакування, якщо це необхідно ( §5.1.8 ), і тип операції буде boolean. &це призведе до того, що trueобидва операнди є true, ^призведе до того, що trueобидва операнди різні, і |призведе до trueтого, що є будь-який операнд true. ( §15.22.2 )
Навпаки, && це "Умовно-І Оператор" ( §15.23 ) і ||є "Умовно-Або Оператор" ( §15.24 ). Їх синтаксис визначається як:
ConditionalAndExpression:
InclusiveOrExpression
ConditionalAndExpression && InclusiveOrExpression
ConditionalOrExpression:
ConditionalAndExpression
ConditionalOrExpression || ConditionalAndExpression
&&є як &, за винятком того, що він оцінює правий операнд лише тоді, коли лівий операнд true. ||є як |, за винятком того, що він оцінює правий операнд лише тоді, коли лівий операндfalse .
Умовно-А має такі властивості:
- Умовно-оператор синтаксично ліво-асоціативний (він групується зліва направо).
- Умовно-оператор є повністю асоціативним щодо побічних ефектів та значення результату. Тобто, для будь-яких виразів
a, bа також c, оцінка виразу ((a) && (b)) && (c)дає той самий результат із тими ж побічними ефектами, що виникають у тому ж порядку, що й оцінка виразу(a) && ((b) && (c)) .
- Кожен операнд умовного і оператора повинен бути типу
booleanабоBoolean , або виникає помилка часу компіляції.
- Тип умовно-вираження завжди
boolean .
- Під час виконання спочатку оцінюється вираз лівого операнду; якщо результат має тип
Boolean, він піддається розгорнутому перетворенню ( §5.1.8 ).
- Якщо отримане значення дорівнює
false, значення умовного і вираження єfalse а правий вираз операнда не оцінюється.
- Якщо значення лівого операнда дорівнює
true, то вираження праворуч оцінюється; якщо результат має тип Boolean, він піддається розгорнутому перетворенню ( §5.1.8 ). Отримане значення стає значенням умовно-вираження.
- Таким чином,
&&обчислюється той самий результат, що і &на booleanоперандах. Він відрізняється лише тим, що вираз правого операнда оцінюється умовно, а не завжди.
Умовно-Або має такі властивості:
- Умовно-або оператор синтаксично ліво-асоціативний (він групується зліва направо).
- Умовно-або оператор є повністю асоціативним щодо побічних ефектів та значення результату. Тобто, для будь-яких виразів
a, bі c, оцінка вираження ((a) || (b)) || (c)дає той самий результат, з тими ж побічними ефектами, що виникають у тому ж порядку, що і оцінка виразу (a) || ((b) || (c)).
- Кожен операнд умовного або оператора повинен бути типу
booleanабо Boolean, або виникає помилка часу компіляції.
- Тип умовного або виразу є завжди
boolean .
- Під час виконання спочатку оцінюється вираз лівого операнду; якщо результат має тип
Boolean, він піддається розгорнутому перетворенню ( §5.1.8 ).
- Якщо отримане значення є
true, значення умовного або виразу є, trueа вираз правого операнда не оцінюється.
- Якщо значення лівого операнда дорівнює
false, то вираження праворуч оцінюється; якщо результат має тип Boolean, він піддається розгорнутому перетворенню ( §5.1.8 ). Отримане значення стає значенням умовного або виразу.
- Таким чином,
||обчислює той же результат, |на booleanабо Booleanоперанди. Він відрізняється лише тим, що вираз правого операнда оцінюється умовно, а не завжди.
Коротше кажучи, як @JohnMeagher неодноразово вказував у коментарях, &і |насправді булові оператори, що не мають короткого замикання, у конкретному випадку операндів є booleanабо Boolean. При належній практиці (тобто відсутність вторинних наслідків) це незначна різниця. Однак, коли операндів немає booleanабо Booleanне, оператори поводяться зовсім інакше: побітові та логічні операції просто не дуже добре порівнюються на високому рівні програмування Java.