&& (AND) e || (OR) nas declarações IF


137

Eu tenho o seguinte código:

if(!partialHits.get(req_nr).containsKey(z) || partialHits.get(req_nr).get(z) < tmpmap.get(z)){  
    partialHits.get(z).put(z, tmpmap.get(z));  
}

Onde partialHitsestá um HashMap.
O que acontecerá se a primeira afirmação for verdadeira? O Java ainda verificará a segunda instrução? Como para que a primeira instrução seja verdadeira, o HashMap não deve conter a chave fornecida, portanto, se a segunda instrução estiver marcada, receberei NullPointerException.
Então, em palavras simples, se tivermos o seguinte código

if(a && b)  
if(a || b)

Java verificaria bse aé falso no primeiro caso e se aé verdadeiro no segundo caso?

Respostas:


202

Não, não será avaliado. E isso é muito útil. Por exemplo, se você precisar testar se uma String não é nula ou vazia, você pode escrever:

if (str != null && !str.isEmpty()) {
  doSomethingWith(str.charAt(0));
}

ou, ao contrário

if (str == null || str.isEmpty()) {
  complainAboutUnusableString();
} else {
  doSomethingWith(str.charAt(0));
}

Se não tivéssemos 'curto-circuitos' em Java, receberíamos muitas NullPointerExceptions nas linhas de código acima.


Existem comparações bit a bit para que você possa avaliar as duas expressões? ou seja, se (str! = null | str.isEmpty ())? (é claro que isso não é um exemplo prático, na verdade, é estúpido, mas você começa a idéia)
— Kezzer

5
Contanto que as expressões não tenham efeitos colaterais, a semântica de curto-circuito é logicamente equivalente à avaliação completa. Ou seja, se A é verdadeiro, você sabe que A || B é verdadeiro sem ter que avaliar B. O único momento em que fará diferença é se uma expressão tiver efeitos colaterais. Quanto a outros operadores, você pode usar *e +como lógico ande or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. Você mesmo pode fazer xor: ((A?1:0) + (B?1:0)) == 1.
— Outis

1
@ Kezzer: essa comparação é realmente bit a bit? Eu acho que é um booleanoperador (lógico). É diferente do que o bitwiseoperador (inteiro), apesar de ter o mesmo símbolo ...
— user85421

4
Um truque útil quando você deseja alternar entre '&&' e '||' expressões é negar toda a expressão, de tal forma que: !(str != null && !str.isEmpty()) torna-se: (str !(!=) null !(&&) !(!)str.isEmpty()) e então: (str == null || str.isEmpty()) porque: !(!=) is == !(&&) is || !(!) eliminates itself outras negações votos são: !(<) is >= !(>) is <= e vice-versa
— egallardo

68

Java possui 5 operadores de comparação booleanos diferentes: &, &&, |, ||, ^

& e && são operadores "e", | e || "ou" operadores, ^ é "xor"

Os únicos verificarão todos os parâmetros, independentemente dos valores, antes de verificar os valores dos parâmetros. Os duplos primeiro verificarão o parâmetro esquerdo e seu valor e se true( ||) ou false( &&) deixarão o segundo intocado. Som compilado? Um exemplo fácil deve deixar claro:

Dados para todos os exemplos:

 String aString = null;

E:

 if (aString != null & aString.equals("lala"))

Ambos os parâmetros são verificados antes da avaliação ser concluída e uma NullPointerException será lançada para o segundo parâmetro.

 if (aString != null && aString.equals("lala"))

O primeiro parâmetro é verificado e retorna false, para que o segundo parâmetro não seja verificado, porque o resultado é o falsemesmo.

O mesmo para OR:

 if (aString == null | !aString.equals("lala"))

Também aumentará NullPointerException.

 if (aString == null || !aString.equals("lala"))

O primeiro parâmetro é verificado e retorna true, para que o segundo parâmetro não seja verificado, porque o resultado é o truemesmo.

O XOR não pode ser otimizado, porque depende dos dois parâmetros.


3
"Java possui 4 operadores de comparação booleanos diferentes: &, &&, |, ||" ... Você está esquecendo ^(xor).
— aioobe

Ah, eu não sabia que também verifica valores booleanos booleanos. Até agora, foi usado apenas para máscaras de bits.
— Codificado em


20

Todas as respostas aqui são ótimas, mas, apenas para ilustrar de onde isso vem, para perguntas como essa, é bom ir para a fonte: a Java Language Specification.

Seção 15:23, Conditional-operador E (&&) , diz:

O operador && é como & (§15.22.2), mas avalia seu operando do lado direito apenas se o valor do operando do lado esquerdo for verdadeiro. [...] No tempo de execução, a expressão do operando esquerdo é avaliada primeiro [...] se o valor resultante for falso, o valor da expressão condicional e for falso e a expressão do operando direito não for avaliada. . Se o valor do operando do lado esquerdo for verdadeiro, a expressão do lado direito será avaliada [...] e o valor resultante se tornará o valor do condicional - e da expressão. Assim, && calcula o mesmo resultado que & em operandos booleanos. Difere apenas no fato de a expressão do operando do lado direito ser avaliada condicionalmente, e não sempre.

E da mesma forma, a Seção 15:24, Operador Condicional-Ou (||) , diz:

O || operador é como | (§15.22.2), mas avalia seu operando do lado direito somente se o valor do operando do lado esquerdo for falso. [...] No tempo de execução, a expressão do operando esquerdo é avaliada primeiro; [...] se o valor resultante for verdadeiro, o valor da expressão condicional ou é verdadeiro e a expressão do operando do lado direito não é avaliada. Se o valor do operando do lado esquerdo for falso, a expressão do lado direito será avaliada; [...] o valor resultante se torna o valor da expressão ou condicional. Assim, || calcula o mesmo resultado que | em operandos booleanos ou booleanos. Difere apenas no fato de a expressão do operando do lado direito ser avaliada condicionalmente, e não sempre.

Um pouco repetitivo, talvez, mas a melhor confirmação de exatamente como eles funcionam. Da mesma forma, o operador condicional (? :) apenas avalia a 'metade' apropriada (metade esquerda se o valor for verdadeiro, metade direita se for falso), permitindo o uso de expressões como:

int x = (y == null) ? 0 : y.getFoo();

sem uma NullPointerException.


6

Não, se a for verdadeiro (em um orteste), b não será testado, pois o resultado do teste sempre será verdadeiro, qualquer que seja o valor da expressão b.

Faça um teste simples:

if (true || ((String) null).equals("foobar")) {
    ...
}

não vai jogar um NullPointerException!


6

Curto-circuito aqui significa que a segunda condição não será avaliada.

Se (A && B) resultará em curto-circuito se A for Falso.

Se (A && B) não resultará em curto-circuito se A for Verdadeiro.

Se (A || B) resultará em curto-circuito se A for Verdadeiro.

Se (A || B) não resultará em curto-circuito se A for Falso.


4

Não, não será, o Java entrará em curto-circuito e deixará de avaliar quando souber o resultado.


4

Sim, a avaliação de curto-circuito para expressões booleanas é o comportamento padrão em toda a família C.

Um fato interessante é que Java também utiliza o &e |como operandos lógicas (eles estão sobrecarregados, com inttipos que são as operações bit a bit esperados) para avaliar todos os termos na expressão, que também é útil quando você precisa dos efeitos colaterais.


É interessante lembrar: por exemplo, dado um método changeData (data) que retorna um booleano, então: if (a.changeData (data) || b.changeData (data)) {doSomething (); } não executa changeData em b se a.changeData () retorna true, mas se (a.changeData (data) | b.changeData (data)) {doSomething ()} executa changeData () em aeb, mesmo se o invocado em um retornado true.
— Sampisa

0

Isso remonta à diferença básica entre & e &&, | e ||

BTW, você executa as mesmas tarefas várias vezes. Não tenho certeza se a eficiência é um problema. Você pode remover parte da duplicação.

Z z2 = partialHits.get(req_nr).get(z); // assuming a value cannout be null.
Z z3 = tmpmap.get(z); // assuming z3 cannot be null.
if(z2 == null || z2 < z3){   
    partialHits.get(z).put(z, z3);   
} 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.