2009-05-12 11 views
8

¿Por qué Func3 no se ejecuta en el programa a continuación? Después de func1, func2 no necesita ser evaluado sino para func3, ¿no es así?¿Qué hay de malo con la lógica de cortocircuito en este código de Java?

if (func1() || func2() && func3()) { 
     System.out.println("true"); 
    } else { 
     System.out.println("false"); 
    } 
} 

public static boolean func1() { 
    System.out.println("func1"); 
    return true; 
} 

public static boolean func2() { 
    System.out.println("func2"); 
    return false; 
} 

public static boolean func3() { 
    System.out.println("func3"); 
    return false; 
} 
+0

creo que no todo el mundo es consciente del problema de cortocircuito, en ese caso la versión editada de la cuestión para no ser de interés los novatos, incluso si están buscando una respuesta con respecto a la lógica && y || evaluación de Java. – DragonBorn

+4

Esto plantea el hecho de que en cualquier tipo de expresión no trivial como esa, es una buena idea declarar su intención entre paréntesis. Entonces, incluso si pretendía (func1() || (func2() && func3()), lo hace explícito y claro para los programadores que vienen después que su código está funcionando como estaba previsto. – mtruesdell

Respuesta

25

Está utilizando un cortocircuito o. Si el primer argumento es verdadero, la expresión completa es verdadera.

Podría ayudar si añado entre paréntesis implícitos que el compilador utiliza

Editar: Como se señaló Chris Jester-Young, esto es en realidad porque los operadores lógicos tienen que de izquierda a derecha asociatividad:

if (func1() || (func2() && func3())) 

Después vuelve Func1, se convierte en esto:

if (true || (func2() && func3())) 

Después de evaluar el corto-circuito o, se convierte en:

if (true) 
+13

Para evitar dudas, esto es porque && tiene una precedencia mayor que ||. La asociatividad es, en ambos casos, de izquierda a derecha. –

+4

Menciono esto porque de lo contrario esta publicación daría lugar a la pregunta de por qué (A || (B && C)) como opuesto a ((A || B) && C). –

+3

(Es importante para la noche que la precedencia que es importante aquí, ninguna asociatividad no se vea. OMI, expresiones como 'a || b && c 'y' a && b || c' (que es '(a && b) || c) son confusos y el compilador debería presentar una queja.) –

3

cortocircuitos de Java expresiones booleanas. Eso significa que, una vez que se ejecuta func1() y devuelve true, el resto de ese booleano no importa ya que está utilizando un operador or. No importa qué evalúe func2() && func3(), la expresión completa evaluará a true. Por lo tanto, Java ni siquiera se molesta en evaluar func2() o func3().

1

respuesta corta: short-circuit evaluation

desde func1() yelds verdad no hay necesidad de continuar la evaluación, ya que siempre es cierto

1

Si la función 1 siempre vuelve cierto, entonces Java no necesita evaluar el resto de la expresión para determinar que toda la expresión será verdadera.

2

Java usa la evaluación Lazy.

Dado que Func1 siempre devuelve verdadero, toda la expresión DEBE ser verdadera, por lo que abrevia el resto de la expresión.

true || (???) 

y

false && (???) 

siempre habrá acceso directo.

Para desactivar la evaluación de acceso directo, use | y & en lugar de || y & &

podemos utilizar este con buenos resultados:

String s; 
if (s != null && !s.equals("")) ... 

Lo que significa que si s es nulo, que ni siquiera tendrá que tratar de llamar s.equals, y no vamos a acabar lanzando una NullPointerException

+0

No siempre será un atajo. Se está evaluando según las reglas de precedencia. Tengo un compilador Java a mano, pero creo que (falsefunc() && true1() || true2()) evaluará falsefunc () luego true2(). – DevinB

+0

Buen punto. Se agregaron paréntesis para corregirlo. –

2

Estás usando los atajos-operadores || y & &.Estos operadores no ejecutan el resto de la expresión, si el resultado ya está definido. Para || eso significa que si la primera expresión es verdadera y para & & si la primera expresión es falsa.

Si desea ejecutar todas las partes de la expresión use | y & en su lugar, eso no es atajo.

funciones
5

Java son evaluados de acuerdo a precedence rules

porque "& &" es de precedencia más alta que "||", se evalúa primero porque no tiene los soportes para fijar la precedencia explícita

por lo que la expresión de

(A || B && C) 

que es

(T || F && F) 

se encuentra entre corchetes como

(T || (F && F)) 

debido a las reglas de prioridad.

Desde el compilador entiende que si 'A == true' no tiene por qué molestar a la evaluación del resto de la expresión, deja tras evaluar A.

Si había corchetes ((A || B) && C) entonces sería evaluar a falso.

EDITAR

Otra forma, como se ha mencionado en otras críticas es utilizar "|" y "&" en lugar de "||" y "& &" porque eso detiene la expresión de acceso directo. Sin embargo, debido a las reglas de precedencia, el resultado final seguirá siendo el mismo.

0

si desea que todas las funciones a ejecutar se puede soltar el atajo variantes

if (func1() | func2() & func3()) { 
Cuestiones relacionadas