2009-11-25 23 views
101

Mi pregunta puede ser muy básica, pero aún así creo que vale la pena preguntar. Tengo el siguiente código:&& (AND) y || (O) en las declaraciones IF

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 partialHits es un HashMap. ¿Qué pasará si la primera afirmación es verdadera? ¿Seguirá Java controlando la segunda declaración? Porque para que la primera declaración sea verdadera, HashMap no debe contener la clave dada, por lo que si la segunda declaración está marcada, obtendré NullPointerException.
Así, en palabras sencillas, si tenemos el siguiente código

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

comprobaría Java b si a es falso en el primer caso y si es cierto a en el segundo caso?

Respuesta

158

No, no será evaluado. Y esto es muy útil. Al igual que usted necesita para poner a prueba, si una cadena no es nulo o vacío, se puede escribir:

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

o, a la inversa

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

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

+0

¿Existen comparaciones bit a bit para que pueda evaluar ambas expresiones? es decir, si (str! = null | str.isEmpty())? (por supuesto, este no es un ejemplo práctico, de hecho es estúpido, pero entiendes la idea) – Kezzer

+5

Siempre que las expresiones no tengan efectos secundarios, la semántica del cortocircuito es lógicamente equivalente a una evaluación completa. Es decir, si A es cierto, usted sabe que A || B es verdadero sin tener que evaluar B. El único momento en que hará una diferencia es si una expresión tiene efectos secundarios. En cuanto a otros operadores, puede usar '*' y '+' como lógico 'y' y' o'; '((A? 1: 0) * (B? 1: 0)) == 1',' ((A? 1: 0) + (B? 1: 0))> 0'. Incluso 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 operador 'boolean' (lógico). Es diferente del operador 'bitwise' (integer), a pesar de tener el mismo símbolo ... –

27

No, no se comprobará. Este comportamiento se llama short-circuit evaluation y es una característica en muchos idiomas, incluido Java.

+2

@Azimuth: Usted es bienvenido. Si no sabe algo, la mejor manera de solucionarlo es preguntar. –

5

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

Hacer una prueba sencilla:

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

se no lanzar una NullPointerException!

4

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

18

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

Section 15:23, Conditional-And operator (&&), dice:

El operador & & es como & (§15.22.2), pero evalúa su operador de la derecha sólo si el valor de su operando de la izquierda es cierto. [...] 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 falsa 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 mano derecha se evalúa [...] el valor resultante se convierte en el valor de la expresión condicional. 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 del mismo modo, Section 15:24, Conditional-Or operator (||), dice:

La || el operador es como | (§15.22.2), pero evalúa su operando de la mano derecha solo si el valor de su operando de la mano 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 expresión condicional 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 mano derecha; [...] el valor resultante se convierte en el valor de la expresión condicional. 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. ? Del mismo modo el operador condicional (:) sólo evalúa la 'mitad' apropiada (mitad izquierda si el valor es verdadero, la mitad derecha si es falsa), lo que permite el uso de expresiones como:

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

sin una NullPointerException.

4

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

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

+0

Esto es interesante de recordar: p. dado un método changeData (data) que devuelve un valor booleano, entonces: if (a.changeData (data) || b.changeData (data)) {doSomething(); } no ejecuta changeData en B si a.changeData() devuelve verdadero, pero si (a.changeData (datos) | b.changeData (datos)) {doSomething()} ejecuta changeData() en tanto ayb, incluso si el invocado en un verdadero devuelto. – Sampisa

51

Java tiene 5 diferentes operadores booleanos: comparar &, & &, |, ||,^

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

Los únicos verifican todos los parámetros, 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 sencillo ejemplo debería dejar claro:

Teniendo en cuenta para todos los ejemplos:

String aString = null; 

Y:

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

Ambos parámetros se comprueban antes de realizar la evaluación y una NullPointerException serán lanzados para el segundo parámetro

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

El primer parámetro se comprueba y se devuelve false, por lo que no se comprobará el segundo parametro, porque el resultado es false de todos modos.

Lo mismo para O:

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

elevará NullPointerException, también.

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

El primer parámetro se comprueba y se devuelve true, por lo que no se comprobará el segundo parametro, porque el resultado es true de todos modos.

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

+2

"Java tiene 4 operadores diferentes de comparación booleana: &, &&, |, ||" ... Se está olvidando '^' (xor). – aioobe

+0

Oh, no sabía que también verifica los valores booleanos booleanos. Solo lo usé para máscaras de bits, hasta ahora. – Hardcoded

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); 
} 
4

El cortocircuito aquí significa que no se evaluará la segunda condición.

Si (A & & B) se producirá un cortocircuito si A es falso.

Si (A & & B) no producirse un cortocircuito si A es verdadera.

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

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

Cuestiones relacionadas