Efeito de um operador bit a bit em um booleano em Java

118

Os operadores bit a bit devem viajar pelas variáveis ​​e operá-las bit a bit. No caso de inteiros, longos, chars, isso faz sentido. Essas variáveis ​​podem conter toda a gama de valores impostos por seu tamanho.

No caso de booleanos, entretanto, um booleano pode conter apenas dois valores. 1 = verdadeiro ou 0 = falso. Mas o tamanho do booleano não está definido. Pode ser tão grande quanto um byte ou tão pequeno quanto um bit.

Então, qual é o efeito de usar um operador bit a bit em um booleano? A JVM essencialmente o traduz para um operador lógico normal e segue em frente? Ele trata o booleano como uma entidade de bit único para o propósito da operação? Ou o resultado é indefinido junto com o tamanho de um booleano?

Daniel Bingham
fonte
1
Acho que você não pode usar um operador bit a bit em um booleano. Apenas em números. Tenho certeza que ~ não funcionará, não sei o que acontece com outros operadores.
Martijn Courteaux
4
Você pode usar alguns deles, acabamos de descobrir um | usado em nosso código legado. Estamos removendo, mas este código compilou e funcionou.
Daniel Bingham
9
Como um está em curto-circuito e o outro não (veja a resposta do mobrule), antes de alterar o | para || você pode querer certificar-se de que as expressões booleanas subsequentes não tenham nenhum efeito colateral que o programador original pretendia sempre executar.
John M Gant

Respostas:

122

Os operadores &, ^e |são operadores bit a bit quando os operandos são tipos integrais primitivos. Eles são operadores lógicos quando os operandos são booleanos e seu comportamento no último caso é especificado. Consulte a seção 15.22.2 da Especificação da linguagem Java para obter detalhes.

Noel Ang
fonte
57
Especificamente, & e ^ e | são os operadores booleanos lógicos sem curto-circuito.
Ken
14
Aqui está um link direto para a seção mencionada acima: docs.oracle.com/javase/specs/jls/se7/html/…
Andy Thomas
Se o acima for verdadeiro, por que ideone.com/oGSF7c está lançando uma exceção de ponteiro nulo? Se o |=operador fosse lógico, o programa nunca deveria ter executado a x.getValue()diretiva.
ikromm
1
@JohnKrommidas, seu x é nulo, e é por isso que você está recebendo um NullPointerException. Você precisa instanciá-lo.
Ben
4
@Ben, como diz @Ken, a lógica não está em curto-circuito, então a segunda parte é avaliada. Portanto, a || x.foo()é seguro se x for nulo, mas a | x.foo()não é. |=segue as mesmas regras que |.
Michael Smith
86

Usar o operador bit a bit pode contornar o comportamento de curto-circuito:

boolean b = booleanExpression1() && booleanExpression2();
boolean b = booleanExpression1() & booleanExpression2();

Se for booleanExpression1()avaliado como false,
booleanExpression2()não será avaliado no primeiro caso e
booleanExpression2()(e quaisquer efeitos colaterais que possa ter) será avaliado no segundo caso,

multidão
fonte
2
E a operação bit a bit executa geralmente mais rápido do que a de curto-circuito (desde que a avaliação seja simples)
rds
1
O bit a bit &será mais rápido, mas a chamada para a segunda função pode ser ignorada com o uso de&&
NatNgs
20

Além do que foi abordado nas outras respostas, é importante notar que &&e ||têm precedência diferente de &e |.

Extraia da tabela de precedência (com a precedência mais alta no topo).

bitwise AND                 &
bitwise exclusive OR        ^
bitwise inclusive OR        |
logical AND                 &&
logical OR                  ||

O que isso significa para você?

Absolutamente nada, contanto que você se atenha a apenas &e |ou apenas &&e ||.

Mas, uma vez que |tem uma precedência mais alta do que &&(em oposição a ||, que tem uma precedência mais baixa), misturá-los livremente pode levar a um comportamento inesperado.

Então a && b | c && dé o mesmo que a && (b | c) && d,
ao contrário do a && b || c && dque seria (a && b) || (c && d).

Para provar que eles não são iguais, considere um extrato da tabela verdade:

a | b | c | d | (b|c) | (a&&b) | (c&&d) | a && (b|c) && d | (a&&b) || (c&&d)
F | T | T | T |   T   |   F    |    T   |         F       |        T
                                                  ^                ^
                                                  |- not the same -|

Se você quiser que OR tenha precedência maior do que AND, poderá usar |e &&junto, mas isso não é recomendado.

Mas você realmente deve colocá-los entre colchetes para esclarecer a precedência sempre que usar símbolos diferentes, ou seja, (a && b) || c(colchetes para esclarecer a precedência), a && b && c(não são necessários colchetes).

Bernhard Barker
fonte
3

Mesmo que funcione, você não deve fazer isso. As especificações da linguagem definem operadores bit a bit apenas quando ambos os operandos são de tipos inteiros primitivos ou ambos são do tipo booleano. Eu diria que para qualquer outro caso os resultados não estão definidos:

http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5228

LeffeBrune
fonte
A questão é sobre booleanos, não sobre primitivos ou uma mistura de primitivos e booleanos.
talonx