75

Esistono due tipi di istruzioni if in java-classic: if {} else {} e stenografia: exp ? value1 : value2. È uno più veloce dell'altro o sono gli stessi?Quale costrutto "se" è più veloce - istruzione o operatore ternario?

dichiarazione:

int x; 
if (expression) { 
    x = 1; 
} else { 
    x = 2; 
} 

ternario operatore:

int x = (expression) ? 1 : 2; 
+33

Immagino che non ci sia assolutamente alcuna differenza. È solo sintassi. A meno che i compilatori non siano un po 'cattivi (o qualcos'altro) e io abbia sbagliato – sinelaw

+4

Hai (micro) fatto un benchmark? Condividi i risultati. – BalusC

+3

Entrambe diventeranno jit'ed. Non ci sarà alcuna differenza. E non preoccuparti di decompilare la roba.La prima cosa che fa HotSpot è eliminare ** tutte ** le ottimizzazioni applicate da javac. –

risposta

93

C'è solo un tipo di istruzione "se" lì. L'altro è un'espressione condizionale. Per quanto riguarda il rendimento migliore: potrebbero compilare lo stesso bytecode, e mi aspetterei che si comportino in modo identico, o così vicino da non voler scegliere l'uno sull'altro in termini di prestazioni.

A volte una dichiarazione if sarà più leggibile, a volte l'operatore condizionale sarà più leggibile. In particolare, consiglierei di utilizzare l'operatore condizionale quando i due operandi sono semplici e senza effetti collaterali, mentre se lo scopo principale dei due rami è i loro effetti collaterali, probabilmente utilizzerei una dichiarazione if.

Ecco un esempio di programma e bytecode:

public class Test { 
    public static void main(String[] args) { 
     int x; 
     if (args.length > 0) { 
      x = 1; 
     } else { 
      x = 2; 
     } 
    } 

    public static void main2(String[] args) { 
     int x = (args.length > 0) ? 1 : 2; 
    } 
} 

Bytecode decompilato con javap -c Test:

public class Test extends java.lang.Object { 
    public Test(); 
    Code: 
     0: aload_0 
     1: invokespecial #1 
     4: return 

    public static void main(java.lang.String[] 
    Code: 
     0: aload_0 
     1: arraylength 
     2: ifle   10 
     5: iconst_1 
     6: istore_1 
     7: goto   12 
     10: iconst_2 
     11: istore_1 
     12: return 

    public static void main2(java.lang.String[ 
    Code: 
     0: aload_0 
     1: arraylength 
     2: ifle   9 
     5: iconst_1 
     6: goto   10 
     9: iconst_2 
     10: istore_1 
     11: return 
} 

Come si può vedere, c'è una leggera differenza in bytecode qui - se si verifica l'istore_1 all'interno della brance o meno (a differenza del mio precedente tentativo estremamente viziato :) ma sarei molto sorpreso se il JITter finisse con un diverso codice nativo.

+0

s/istruzione condizionale/espressione condizionale/ –

+0

@Laurence: Doh - grazie, corretto. –

+1

Suppongo che non intendevi per 'main' e' main2' essere esattamente uguali? – ColinD

4

né - saranno compilati allo stesso.

10

Entrambi i vostri esempi verranno probabilmente compilati con il bytecode identico o quasi identico, quindi non ci dovrebbero essere differenze nelle prestazioni.

Se ci fosse stata una differenza nella velocità di esecuzione, dovresti comunque usare la versione più idiomatica (che sarebbe la seconda per assegnare una singola variabile basata su una semplice condizione e due semplici sotto-espressioni, e la prima per fare operazioni o operazioni più complesse che non si adattano a una singola linea).

+0

-1 Per essere sbagliato. Se pretendi che due parti di codice vengano compilate nello stesso codice byte senza nemmeno fornire un qualificatore come "probabilmente" o "Penso", potresti almeno verificare effettivamente che lo facciano. Anche se essi * fanno * compilano lo stesso bytecode, ciò non garantisce che altre versioni del compilatore Java non possano essere compilate con codice byte diverso. – Brian

+0

@Brian: hai ragione. Ho modificato la mia risposta. –

+5

OK, ho rimosso il mio -1 :) – Brian

7

Questi sono gli stessi. Entrambi sono abbastanza veloci, in genere intorno ai 10-30 nano secondi. (a seconda del modello di utilizzo) Questo periodo è importante per te?

Dovresti fare ciò che ritieni più chiaro.

3

Giusto per aggiungere a tutte le altre risposte:

La seconda espressione è spesso chiamato terziario/operatore ternario/dichiarazione. Può essere molto utile perché restituisce un'espressione. A volte rende il codice più chiaro per le frasi brevi tipiche.

+3

Un grande esempio di ciò nella pratica: in Java, se devo fare una stringa finale basata sul risultato di un'espressione, posso usare il sintassi ternaria stringa finale whichTable = (Integer.parseInt (clientId)> 500)? "serverClients": "offlineClients"; Quindi posso usare il valore dell'espressione in luoghi in cui qualeTabella deve essere definitiva. Quanto segue sarebbe illegale: final String whichTable = ""; if (Integer.parseInt (clientId)> 500) { whichTable = "serverClients"; } else { whichTable = "offlineClients"; } –

+0

@JamesPerih Esattamente. – Secko