&& (AND) y || (O) en declaraciones IF

137

Tengo el siguiente 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));  
}

donde partialHitses un HashMap
¿Qué pasará si la primera afirmación es verdadera? ¿Java aún verificará la segunda declaración? Porque para que la primera declaración sea verdadera, el HashMap no debe contener la clave dada, por lo que si la segunda declaración está marcada, obtendré NullPointerException.
En palabras simples, si tenemos el siguiente código

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

¿Java comprobaría bsi aes falso en el primer caso y si aes verdadero en el segundo caso?

Azimut
fuente

Respuestas:

202

No, no será evaluado. Y esto es muy útil. Por ejemplo, si necesita probar si una Cadena no es nula o está vacía, puede escribir:

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

O al revés

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

Si no tuviéramos 'cortocircuitos' en Java, recibiríamos muchas NullPointerExceptions en las líneas de código anteriores.

Andreas Dolk
fuente
¿Existen comparaciones bit a bit para que pueda evaluar ambas expresiones? es decir, si (str! = null | str.isEmpty ())? (por supuesto, esto no es un ejemplo práctico, de hecho, es una estupidez, pero se entiende la idea)
Kezzer
55
Mientras las expresiones no tengan efectos secundarios, la semántica de cortocircuito es lógicamente equivalente a la evaluación completa. Es decir, si A es verdadero, usted sabe que A || B es verdadero sin tener que evaluar B. La única vez que marcará la diferencia es si una expresión tiene efectos secundarios. En cuanto a otros operadores, puede usar *y +como lógico andy or; ((A?1:0) * (B?1:0)) == 1, ((A?1:0) + (B?1:0)) > 0. Incluso se puede hacer xor: ((A?1:0) + (B?1:0)) == 1.
outis
1
@Kezzer: ¿es realmente una comparación bit a bit? Creo que es un booleanoperador (lógico). Es diferente que el bitwiseoperador (entero), a pesar de tener el mismo símbolo ...
user85421
44
Un truco útil cuando quieres cambiar entre '&&' y '||' expresiones es negar toda la expresión, de tal manera que: se !(str != null && !str.isEmpty()) convierte en: (str !(!=) null !(&&) !(!)str.isEmpty()) y luego: (str == null || str.isEmpty()) porque: !(!=) is == !(&&) is || !(!) eliminates itself otras negaciones útiles son: !(<) is >= !(>) is <= y viceversa
egallardo
68

Java tiene 5 operadores booleanos de comparación diferentes: &, &&, |, ||, ^

& y && son operadores "y", | y || "u" operadores, ^ es "xor"

Los únicos verificarán cada parámetro, independientemente de los valores, antes de verificar los valores de los parámetros. Los dobles primero verifican el parámetro izquierdo y su valor y si true( ||) o false( &&) dejan el segundo sin tocar. ¿Sonido compilado? Un ejemplo sencillo debería aclararlo:

Dado para todos los ejemplos:

 String aString = null;

Y:

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

Ambos parámetros se verifican antes de que se realice la evaluación y se lanzará una NullPointerException para el segundo parámetro.

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

El primer parámetro se verifica y regresa false, por lo que el segundo parámetro no se verificará porque el resultado es de falsetodos modos.

Lo mismo para OR:

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

También generará NullPointerException.

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

El primer parámetro se verifica y regresa true, por lo que el segundo parámetro no se verificará porque el resultado es de truetodos modos.

XOR no se puede optimizar, porque depende de ambos parámetros.

Codificado
fuente
3
"Java tiene 4 operadores booleanos de comparación diferentes: &, &&, |, ||" ... Te estás olvidando ^(xor).
aioobe
Oh, no sabía que también verificaba los valores booleanos. Solo lo usé para máscaras de bits, hasta ahora.
Codificado
27

No, no se comprobará. Este comportamiento se denomina evaluación de cortocircuito y es una característica en muchos idiomas, incluido Java.

Peter van der Heijden
fuente
20

Todas las respuestas aquí son geniales, pero, solo para ilustrar de dónde viene esto, para preguntas como esta es bueno ir a la fuente: la Especificación del lenguaje Java.

La Sección 15:23, Operador condicional y (&&) , dice:

El operador && es como & (§15.22.2), pero evalúa su operando de la derecha solo si el valor de su operando de la izquierda es verdadero. [...] En tiempo de ejecución, la expresión del operando de la izquierda se evalúa primero [...] si el valor resultante es falso, el valor de la expresión condicional y es falso y la expresión del operando de la derecha no se evalúa . Si el valor del operando de la izquierda es verdadero, entonces la expresión de la derecha se evalúa [...] y el valor resultante se convierte en el valor de la expresión condicional y. Por lo tanto, && calcula el mismo resultado que & en operandos booleanos. Solo difiere en que la expresión del operando de la derecha se evalúa condicionalmente en lugar de siempre.

Y de manera similar, la Sección 15:24, Operador Condicional-O (||) , dice:

El || operador es como | (§15.22.2), pero evalúa su operando de la derecha solo si el valor de su operando de la izquierda es falso. [...] En tiempo de ejecución, la expresión del operando de la izquierda se evalúa primero; [...] si el valor resultante es verdadero, el valor de la condicional-o expresión es verdadero y la expresión del operando de la derecha no se evalúa. Si el valor del operando de la izquierda es falso, entonces se evalúa la expresión de la derecha; [...] el valor resultante se convierte en el valor de la condicional-o expresión. Por lo tanto, || calcula el mismo resultado que | en operandos booleanos o booleanos. Solo difiere en que la expresión del operando de la derecha se evalúa condicionalmente en lugar de siempre.

Un poco repetitivo, tal vez, pero la mejor confirmación de cómo funcionan exactamente. De manera similar, el operador condicional (? :) solo evalúa la 'mitad' apropiada (mitad izquierda si el valor es verdadero, mitad derecha si es falso), permitiendo el uso de expresiones como:

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

sin una excepción NullPointerException.

Cowan
fuente
6

No, si a es verdadero (en una orprueba), b no se probará, ya que el resultado de la prueba siempre será verdadero, sea cual sea el valor de la expresión b.

Haz una prueba simple:

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

será no lanzar una NullPointerException!

Romain Linsolas
fuente
6

Cortocircuito aquí significa que la segunda condición no será evaluada.

Si (A y B) dará como resultado un cortocircuito si A es falso.

Si (A y B) no generará un cortocircuito si A es verdadero.

Si (A || B) provocará un cortocircuito si A es verdadero.

Si (A || B) no provocará un cortocircuito si A es falso.

usuario3211238
fuente
4

No, no lo hará, Java hará un cortocircuito y dejará de evaluar una vez que sepa el resultado.

abyx
fuente
4

Sí, la evaluación de cortocircuito para expresiones booleanas es el comportamiento predeterminado en toda la familia tipo C.

Un hecho interesante es que Java también usa los &y |como operandos lógicos (están sobrecargados, con inttipos son las operaciones bit a bit esperadas) para evaluar todos los términos en la expresión, lo que también es útil cuando necesita los efectos secundarios.

fortran
fuente
Es interesante recordar esto: por ejemplo, dado un método changeData (datos) que devuelve un valor booleano, entonces: if (a.changeData (datos) || b.changeData (datos)) {doSomething (); } no ejecuta changeData en b si a.changeData () devuelve verdadero, pero si (a.changeData (datos) | b.changeData (datos)) {doSomething ()} ejecuta changeData () en ayb, incluso si el invocado en un verdadero devuelto.
Sampisa
0

Esto se remonta a la diferencia básica entre & y &&, | y ||

Por cierto, realiza las mismas tareas muchas veces. No estoy seguro si la eficiencia es un problema. Puede eliminar parte de la duplicación.

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
fuente