As outras respostas fizeram um bom trabalho ao cobrir a diferença funcional entre os operadores, mas as respostas podem se aplicar a praticamente todas as linguagens derivadas de C existentes hoje. A pergunta está marcada comJavae, por isso, tentarei responder específica e tecnicamente à linguagem Java.
&
e |
podem ser operadores inteiros bit a bit ou operadores lógicos booleanos. A sintaxe para os operadores bit a bit e lógicos ( §15.22 ) é:
AndExpression:
EqualityExpression
AndExpression & EqualityExpression
ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression ^ AndExpression
InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression | ExclusiveOrExpression
A sintaxe para EqualityExpression
é definida no §15.21 , que requer RelationalExpression
definido no §15.20 , que por sua vez requer ShiftExpression
e ReferenceType
definido nos §15.19 e §4.3 , respectivamente. ShiftExpression
Os requisitos AdditiveExpression
definidos no §15.18 , que continuam a detalhar, definindo a aritmética básica, os operadores unários, etc. detalham ReferenceType
todas as várias maneiras de representar um tipo. (Embora ReferenceType
não inclua os tipos primitivos, a definição de tipos primitivos é finalmente necessária, pois eles podem ser o tipo de dimensão para uma matriz, que é a ReferenceType
.)
Os operadores bit a bit e lógicos têm as seguintes propriedades:
- Esses operadores têm precedência diferente, com
&
a maior e |
a menor precedência.
- Cada um desses operadores é sintaticamente associativo à esquerda (cada grupo da esquerda para a direita).
- Cada operador é comutativo se as expressões do operando não tiverem efeitos colaterais.
- Cada operador é associativo.
- Os operadores bit a bit e lógicos podem ser usados para comparar dois operandos do tipo numérico ou dois operandos do tipo
boolean
. Todos os outros casos resultam em um erro em tempo de compilação.
A distinção entre se o operador serve como operador bit a bit ou operador lógico depende se os operandos são "conversíveis em um tipo integral primitivo" ( §4.2 ) ou se são do tipo boolean
ou Boolean
( §5.1.8 ).
Se os operandos são do tipo integral, a promoção numérica binária ( §5.6.2 ) é realizada nos dois operandos, deixando-os como long
s ou int
s para a operação. O tipo da operação será o tipo dos operandos (promovidos). Nesse ponto, &
será AND bit a bit, ^
será OR bit a bit exclusivo e |
será OR bit a bit, inclusive. ( §15.22.1 )
Se os operandos forem boolean
ou Boolean
, os operandos estarão sujeitos à conversão de unboxing, se necessário ( §5.1.8 ), e o tipo da operação será boolean
. &
resultará em true
se ambos os operandos forem true
, ^
resultará em true
se ambos operandos forem diferentes e |
resultará em true
se qualquer operando for true
. ( §15.22.2 )
Por outro lado, &&
é o "Operador condicional-E" ( §15.23 ) e ||
é o " Operador condicional-E " ( §15.24 ). Sua sintaxe é definida como:
ConditionalAndExpression:
InclusiveOrExpression
ConditionalAndExpression && InclusiveOrExpression
ConditionalOrExpression:
ConditionalAndExpression
ConditionalOrExpression || ConditionalAndExpression
&&
é como &
, exceto que ele avalia apenas o operando direito se o operando esquerdo estiver true
. ||
é como |
, exceto que ele avalia apenas o operando direito se o operando esquerdo estiver false
.
Condicional-E tem as seguintes propriedades:
- O operador condicional e é associativamente à esquerda sintaticamente (agrupa da esquerda para a direita).
- O operador condicional e é totalmente associativo em relação aos efeitos colaterais e ao valor do resultado. Ou seja, para qualquer expressão
a
, b
e c
avaliação da expressão ((a) && (b)) && (c)
produz o mesmo resultado, com os mesmos efeitos colaterais ocorrendo na mesma ordem, como avaliação da expressão (a) && ((b) && (c))
.
- Cada operando do operador condicional e deve ser do tipo
boolean
ou Boolean
, ou ocorre um erro em tempo de compilação.
- O tipo de uma expressão condicional e é sempre
boolean
.
- No tempo de execução, a expressão do operando do lado esquerdo é avaliada primeiro; se o resultado tiver um tipo
Boolean
, ele estará sujeito à conversão de unboxing ( §5.1.8 ).
- Se o valor resultante for
false
, o valor da expressão condicional e é false
e a expressão do operando do lado direito não é avaliada.
- Se o valor do operando do lado esquerdo for
true
, a expressão do lado direito será avaliada; se o resultado tiver um tipo Boolean
, ele estará sujeito à conversão de unboxing ( §5.1.8 ). O valor resultante se torna o valor da expressão condicional-e.
- Assim,
&&
calcula o mesmo resultado que &
nos boolean
operandos. Difere apenas no fato de a expressão do operando do lado direito ser avaliada condicionalmente, e não sempre.
Condicional-Or tem as seguintes propriedades:
- O operador condicional ou é associativamente à esquerda sintaticamente (agrupa da esquerda para a direita).
- O operador condicional ou é totalmente associativo em relação aos efeitos colaterais e ao valor do resultado. Ou seja, para qualquer expressão
a
, b
e c
avaliação da expressão ((a) || (b)) || (c)
produz o mesmo resultado, com os mesmos efeitos colaterais ocorrendo na mesma ordem, como avaliação da expressão (a) || ((b) || (c))
.
- Cada operando do operador condicional ou deve ser do tipo
boolean
ou Boolean
, ou ocorre um erro em tempo de compilação.
- O tipo de uma expressão condicional ou é sempre
boolean
.
- No tempo de execução, a expressão do operando do lado esquerdo é avaliada primeiro; se o resultado tiver um tipo
Boolean
, ele estará sujeito à conversão de unboxing ( §5.1.8 ).
- Se o valor resultante for
true
, o valor da expressão condicional ou é true
e a expressão do operando do lado direito não é avaliada.
- Se o valor do operando do lado esquerdo for
false
, a expressão do lado direito será avaliada; se o resultado tiver um tipo Boolean
, ele estará sujeito à conversão de unboxing ( §5.1.8 ). O valor resultante se torna o valor da expressão condicional-ou.
- Assim,
||
calcula o mesmo resultado que |
on boolean
ou Boolean
operandos. Difere apenas no fato de a expressão do operando do lado direito ser avaliada condicionalmente, e não sempre.
Resumindo, como @JohnMeagher apontou repetidamente nos comentários, &
e |
são, de fato, operadores booleanos sem curto-circuito no caso específico dos operandos serem um boolean
ou outro Boolean
. Com boas práticas (ou seja, sem efeitos secundários), essa é uma pequena diferença. Quando os operandos não são boolean
s ou Boolean
s, no entanto, os operadores se comportam de maneira muito diferente: as operações bit a bit e lógicas simplesmente não se comparam bem no alto nível da programação Java.