Diferenças nos operadores booleanos: & vs && e | vs ||

Respostas:

134

Esses são os operadores bit a bit AND e bit a bit OR.

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

Obrigado a Carlos por apontar a seção apropriada nas especificações da linguagem Java ( 15.22.1 , 15.22.2 ) sobre os diferentes comportamentos do operador com base em suas entradas.

De fato, quando ambas as entradas são booleanas, os operadores são considerados Operadores Lógicos Booleanos e se comportam de maneira semelhante aos operadores Conditional-And ( &&) e Conditional-Or ( ||), exceto pelo fato de que eles não entram em curto-circuito, portanto, o seguinte é seguro :

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

Isso não é:

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

"Curto-circuito" significa que o operador não examina necessariamente todas as condições. Nos exemplos acima, &&examinará a segunda condição somente quando anão for null(caso contrário, toda a declaração retornará falsa, e seria discutível examinar as seguintes condições de qualquer maneira), então a declaração de a.somethingnão levantará uma exceção ou é considerada "segura . "

O &operador sempre examina todas as condições da cláusula, portanto, nos exemplos acima, a.somethingpode ser avaliada quando aé de fato um nullvalor, gerando uma exceção.

Justin Niessner
fonte
1
queria esclarecer .. e retornará 1 apenas se AMBOS forem 1? 101 e 001 seriam 001? Certo?
gideon
@giddy @Jonathon - Atualizei meus valores para mostrar melhor essa situação.
Justin Niessner,
incompleto: eles também são operadores LÓGICOS (para booleanos).
user85421
1
@ Carlos- Não. Eles ainda são operadores bit a bit. Eles apenas se comportam da mesma forma que os operadores lógicos sem curto-circuito. Há uma diferença.
Justin Niessner
4
e quais são os operadores lógicos sem curto-circuito? Os operadores & e | (solicitado pelo OP) são "Operadores Bitwise Inteiros" (JLS 15.22.1) e "Operadores lógicos booleanos" (JLS 15.22.2). Ou a Especificação da linguagem Java está errada sobre isso?
user85421
108

Acho que você está falando sobre o significado lógico de ambos os operadores, aqui você tem um resumo da tabela:

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

Avaliação de curto-circuito , avaliação mínima ou avaliação de McCarthy (após John McCarthy) é a semântica de alguns operadores booleanos em algumas linguagens de programação em que o segundo argumento é executado ou avaliado apenas se o primeiro argumento não for suficiente para determinar o valor do expressão: quando o primeiro argumento da função AND é avaliado como falso, o valor geral deve ser falso; e quando o primeiro argumento da função OR for avaliado como verdadeiro, o valor geral deve ser verdadeiro.

Não seguro significa que o operador sempre examina todas as condições na cláusula, portanto, nos exemplos acima, 1 / x pode ser avaliado quando x é, de fato, um valor 0, gerando uma exceção.

Torres
fonte
1
@Torres - expanda sua resposta explicando "curto-circuito" e "seguro". Também é "exclusivo ou" e "lógico não" também "não está em curto-circuito"? E por que é chamado de "não lógico" em vez de "não lógico booleano"? E por que o "NÃO lógico" não está agrupado com o "E lógico" e o "OU lógico"? Boa resposta, mas precisa ser corrigida.
tfmontague
@tfmontague, eu expliquei o que significa curto-circuito (editando esta resposta) .. Esperando que minha edição seja "revisada por pares".
Taslim Oseni
o que é "inseguro" em não entrar em curto-circuito? não deveria ser mais seguro do que usar curto-circuitos? A propósito: você realmente não explica o termo "curto-circuito". isso significa que em "não curto-circuito" todas as partes são avaliadas primeiro, então a operação booleana é aplicada, enquanto em curto-circuito a avaliação é interrompida, quando a primeira expressão satisfaz a condição, como (a || b) não avalie b, se a for verdadeiro e a operação ou retornará verdadeiro, não importa o que b seja.
SCI de
26

Sei que há muitas respostas aqui, mas todas parecem um pouco confusas. Então, depois de fazer algumas pesquisas no guia de estudo do oráculo Java, eu vim com três cenários diferentes de quando usar && ou &. Os três cenários são AND lógico , AND bit a bit e AND booleano .

E lógico: E lógico (também conhecido como E condicional) usa o operador && . É o significado de curto-circuito: se o operando esquerdo for falso, o operando direito não será avaliado.
Exemplo:

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

No exemplo acima, o valor impresso no console de x será 0, porque o primeiro operando na instrução if é falso, portanto, java não precisa calcular (1 == ++ x), portanto, x não será calculado.

AND bit a bit: AND bit a bit usa o operador & . É usado para executar uma operação bit a bit no valor. É muito mais fácil ver o que está acontecendo observando a operação em números binários, por exemplo:

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

Como você pode ver no exemplo, quando as representações binárias dos números 5 e 12 estão alinhadas, um AND bit a bit pré-formado produzirá apenas um número binário onde o mesmo dígito em ambos os números tem um 1. Portanto, 0101 & 1100 == 0100. Que em decimal é 5 e 12 == 4.

AND booleano: agora, o operador AND booleano se comporta de maneira semelhante e diferente tanto para o AND bit a bit quanto para o AND lógico. Eu gosto de pensar nisso como a execução de um AND bit a bit entre dois valores booleanos (ou bits), portanto, ele usa o operador & . Os valores booleanos também podem ser o resultado de uma expressão lógica.

Ele retorna um valor verdadeiro ou falso, muito parecido com o AND lógico, mas ao contrário do AND lógico, não é curto-circuitado. A razão é que, para executar aquele AND bit a bit, ele deve saber o valor dos operandos esquerdo e direito. Aqui está um ex:

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

Agora, quando essa instrução if for executada, a expressão (1 == ++ x) será executada, mesmo que o operando esquerdo seja falso. Portanto, o valor impresso para x será 1 porque foi incrementado.

Isso também se aplica a OR lógico (||), OR bit a bit (|) e OR booleano (|) Espero que isso esclareça alguma confusão.

LynchburgExplorer
fonte
to preform that bitwise AND, it must know the value of both left and right operandsIsso não parece certo para mim. Para executar um, BITWISE ANDvocê não precisa saber o operando direito para poder descobrir o resultado se o operando esquerdo for FALSE. O que você explica está correto, mas o raciocínio que você afirma não parece ser, pelo menos para mim ..
Koray Tugay
7

Os operadores && e || estão em curto-circuito, o que significa que não avaliarão a expressão da mão direita se o valor da expressão da mão esquerda for suficiente para determinar o resultado.

Tassos Bassoukos
fonte
7
-1 por dizer ao OP o que ele já sabia e não responder à pergunta que ele realmente fez.
Alnitak,
5

& e | fornecem o mesmo resultado que && e || operadores. A diferença é que eles sempre avaliam ambos os lados da expressão onde como && e || pare de avaliar se a primeira condição é suficiente para determinar o resultado.

Brian Scott
fonte
1
Errado .... Pois &&ele avalia os dois resultados, enquanto ||retorna apenas se a primeira condição for verdadeira.
Buhake Sindi,
1
Hã? O && só avalia o lado direito da expressão se o lado esquerdo já for verdadeiro. Caso contrário, ele para de ser avaliado como o primeiro falso implicitamente significa que o resultado não pode ser verdadeiro. Consulte jguru.com/faq/view.jsp?EID=16530
Brian Scott,
1
( 2 & 4 )avalia para false, enquanto ( 2 && 4 )avalia para true. Como exatamente esse é o mesmo resultado?
Piskvor saiu do prédio em
1
@Piskvor - não em Java! 2 & 4resulta em um inteiro, não um booleano (zero neste caso). 2 && 4não irá compilar, && apenas aceita booleanos. Java não permite misturar booleanos e ints: zero não é false, falsenão é zero ...
user85421
1
@BuhakeSindi Wrong. Pois &&ele só avalia o segundo operando se o primeiro operando for true.
Marquês de Lorne
2

Em Java, os operadores únicos &, |, ^,! dependem dos operandos. Se ambos os operandos forem ints, uma operação bit a bit será executada. Se ambos forem booleanos, uma operação "lógica" será executada.

Se ambos os operandos forem incompatíveis, um erro de tempo de compilação será gerado.

Os operadores duplos &&, || se comportam de maneira semelhante a suas contrapartes únicas, mas ambos os operandos devem ser expressões condicionais, por exemplo:

if ((a <0) && (b <0)) {...} ou similarmente, if ((a <0) || (b <0)) {...}

fonte: linguagem de programação java 4ª ed

aaron p.
fonte
1

Talvez seja útil saber que os operadores AND bit a bit e OR bit a bit são sempre avaliados antes do AND condicional e do OR condicional usados ​​na mesma expressão.

if ( (1>2) && (2>1) | true) // false!
alexmeia
fonte
1
você quer dizer prioridade do operador ao invés de ordem de avaliação? Eu preferiria não ver a diferença de prioridade usada no código real. Use parênteses em vez de operadores bit a bit para esse propósito.
John Dvorak
1

&&; || são operadores lógicos ... curto-circuito

&; | são operadores lógicos booleanos ... Não curto-circuito

Movendo para diferenças na execução de expressões. Operadores bit a bit avaliam ambos os lados independentemente do resultado do lado esquerdo. Mas, no caso de avaliar expressões com operadores lógicos, a avaliação da expressão do lado direito depende da condição do lado esquerdo.

Por exemplo:

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

Isso imprimirá i = 26; j = 25, Como a primeira condição é falsa, a condição do lado direito é ignorada, pois o resultado é falso de qualquer maneira, independentemente da condição do lado direito. (curto-circuito)

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

Mas, isso imprimirá i = 26; j = 26,

Nickhil
fonte
0

Se uma expressão envolvendo o operador booleano & for avaliada, ambos os operandos serão avaliados. Em seguida, o operador & é aplicado ao operando.

Quando uma expressão envolvendo o operador && é avaliada, o primeiro operando é avaliado. Se o primeiro operando for avaliado como falso, a avaliação do segundo operando será ignorada.

Se o primeiro operando retornar um valor verdadeiro, o segundo operando será avaliado. Se o segundo operando retornar um valor verdadeiro, o operador && é então aplicado ao primeiro e ao segundo operandos.

Semelhante para | e ||.

RishiKesh Pathak
fonte
0

Embora a diferença básica seja que &é usado principalmente para operações bit a bit long, intou byteonde pode ser usado para uma espécie de máscara, os resultados podem ser diferentes, mesmo se você usá-lo em vez de lógico &&.

A diferença é mais perceptível em alguns cenários:

  1. Avaliar algumas das expressões consome tempo
  2. A avaliação de uma das expressões só pode ser feita se a anterior for verdadeira
  3. As expressões têm algum efeito colateral (intencional ou não)

O primeiro ponto é bastante direto, não causa bugs, mas leva mais tempo. Se você tiver várias verificações diferentes em uma instrução condicional, coloque à esquerda aquelas que são mais baratas ou com maior probabilidade de falhar.

Para o segundo ponto, veja este exemplo:

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

Isso falha null, pois a avaliação da segunda expressão produz a NullPointerException. O operador lógico &&é preguiçoso; se o operando esquerdo for falso, o resultado será falso, independentemente do operando direito.

Exemplo para o terceiro ponto - digamos que temos um aplicativo que usa DB sem gatilhos ou cascatas. Antes de remover um objeto Edifício, devemos mudar o edifício de um objeto Departamento para outro. Digamos também que o status da operação seja retornado como um booleano (verdadeiro = sucesso). Então:

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

Isso avalia ambas as expressões e, portanto, executa a remoção do edifício, mesmo se a atualização do departamento falhou por algum motivo. Com &&, ele funciona como pretendido e para após a primeira falha.

Quanto a a || b, é equivalente a !(!a && !b), pára se afor verdade, nenhuma explicação mais necessária.

Vlasec
fonte