2009-05-12 1 views
8

Perché func3 non viene eseguito nel programma qui sotto? Dopo func1, func2 non ha bisogno di essere valutato ma per func3, non dovrebbe?Cosa c'è di sbagliato nella logica di corto circuito in questo codice 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

credo che non tutti sono a conoscenza del problema di cortocircuito, in questo caso la versione modificata della questione non potrebbe interessi i neofiti anche se stanno cercando una risposta per quanto riguarda la logica && e || valutazione di Java. – DragonBorn

+4

Ciò solleva il fatto che in qualsiasi tipo di espressione non banale come quella, è una buona idea dichiarare il proprio intento con parentesi. Quindi, anche se intendevi (func1() || (func2() && func3()), rendi esplicito e chiaro ai programmatori che arrivano più tardi che il tuo codice funziona come previsto. – mtruesdell

risposta

25

Si sta utilizzando un cortocircuito o. Se il primo argomento è vero, l'intera espressione è vera.

Potrebbe aiutare se aggiungo le parentesi impliciti che il compilatore utilizza

Edit: Come ha osservato Chris Jester-Young, questo è in realtà perché gli operatori logici devono da sinistra a destra associatività:

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

Dopo rendimenti func1, diventa in questo modo:

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

Dopo aver valutato il corto circuito o, diventa:

if (true) 
+13

A scanso di equivoci, questo è perché && ha precedenza più alta di ||. L'associatività è, in entrambi i casi, da sinistra a destra. –

+4

Lo dico perché altrimenti questo post porterebbe alla domanda di, perché (A || (B && C)) come opposto a ((A || B) && C). –

+3

(È importante per la notte che è la precedenza che è importante qui, nessuna associatività non viene visualizzata. IMO, espressioni come 'a || b && c 'e' a && b || c' (che è '(a && b) || c) sono confusi e il compilatore dovrebbe lamentarsi.) –

3

espressioni booleane di cortocircuito Java. Ciò significa che, una volta eseguito func1() e restituito true, il resto di tale valore booleano non ha importanza dal momento che si sta utilizzando un operatore or. Indipendentemente da ciò che valuta func2() && func3(), l'intera espressione verrà valutata su true. Pertanto, Java non si preoccupa nemmeno di valutare func2() o func3().

1

risposta breve: short-circuit evaluation

dal FUNC1() yelds vero non v'è necessità di continuare la valutazione dal momento che è sempre vero

1

se la funzione 1 sempre restituisce true, quindi Java non ha bisogno di valutare il resto dell'espressione per determinare che l'intera espressione sarà vera.

2

Java utilizza la valutazione Lazy.

Poiché Func1 restituisce sempre true, l'intera espressione DEVE essere vera, quindi consente di collegare il resto dell'espressione.

true || (???) 

e

false && (???) 

sarà sempre scorciatoia.

Per disattivare la valutazione del collegamento, utilizzare | e & invece di || e & &

possiamo usare questo a buon effetto:

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

Il che significa che se s è nullo, noi non hanno nemmeno bisogno di provare a chiamare s.equals, e noi non finiremo lancio di una NullPointerException

+0

Non è sempre un collegamento. Sta valutando in base alle regole di precedenza. t avere un compilatore java a portata di mano, ma credo che (falsefunc() && true1() || true2()) valuterà il falso () quindi true2(). – DevinB

+0

Buon punto. Aggiunte parentesi per correggerlo. –

2

Stai utilizzando gli operatori di scorciatoia || e & &.Questi operatori non eseguono il resto dell'espressione, se il risultato è già definito. Per || ciò significa che se la prima espressione è vera e per & & se la prima espressione è falsa.

Se si desidera eseguire tutte le parti dell'espressione, utilizzare | e & invece, non è una scorciatoia.

funzioni
5

Java sono valutati secondo precedence rules

perché "& &" è di precendenza superiore "||", è valutata in primo luogo perché non avete avuto eventuali staffe per impostare esplicitamente la precedenza

così si espressione di

(A || B && C) 

che è

(T || F && F) 

è tra parentesi come

(T || (F && F)) 

a causa delle regole di precedenza.

Dal momento che il compilatore capisce che se 'A == true' non ha bisogno di preoccuparsi valutare il resto dell'espressione, smette dopo aver valutato A.

Se tu avessi parentesi ((A || B) && C) Poi si sarebbe valutato come falsa.

EDIT

Un altro modo, come detto da altri manifesti è quello di utilizzare "|" e "&" anziché "||" e "& &" perché ciò interrompe l'espressione dalla scorciatoia. Tuttavia, a causa delle regole di precedenza, il risultato finale sarà sempre lo stesso.

0

Se si desidera che tutte le funzioni da eseguire è possibile eliminare la scorciatoia varianti

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