&& (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?

Azimute
fonte

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.

Andreas Dolk
fonte
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.

Codificado
fonte
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.

Cowan
fonte
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!

Romain Linsolas
fonte
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.

user3211238
fonte
4

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

abyx
fonte
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.

fortran
fonte
É 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);   
} 
Peter Lawrey
fonte