2015-07-30 12 views
8

Ci scusiamo se si tratta di una domanda per principianti ma non sono riuscito a trovare una risposta. è meglio fare questo:Variabili locali prima dei rendiconti, è importante?

int result = number/number2; 
return result; 

o:

return number/number2; 

So interi utilizzano la memoria in modo da sto indovinando che sarà diminuire leggermente le prestazioni? Ma d'altra parte rende le cose più chiare, specialmente quando l'int/string è un calcolo lungo.

Grazie per qualsiasi input!

+6

A meno che non si stia veramente cercando di ottimizzare le prestazioni, è sempre necessario dare la priorità alla leggibilità. – Gnarlywhale

+1

Immagino che non usereste un helper int con qualcosa di semplice come numero/numero2? – SJ19

+1

La dichiarazione di una variabile locale aiuta nel debug quando si desidera ispezionare il valore restituito prima di lasciare la funzione. – HDave

risposta

13

Esiste in realtà una regola SonarQube ereditata da PMD chiamata Unnecessary Local Before Return che parla di questo. Dice:

Evitare inutilmente la creazione di variabili locali.

Questa regola è stata later replaced da SSLR regola Variables should not be declared and then immediately returned or thrown, che mantiene la stessa posizione:

Dichiarazione di variabile solo per tornare immediatamente o gettarlo è una pratica cattiva . Alcuni sviluppatori sostengono che la pratica migliora la leggibilità del codice , perché consente loro di nominare esplicitamente ciò che viene restituito . Tuttavia, questa variabile è un dettaglio di implementazione interna che non è esposto ai chiamanti del metodo. Il nome del metodo dovrebbe essere sufficiente per consentire ai chiamanti di sapere esattamente quale sarà il restituito.

E sono assolutamente d'accordo.

IntelliJ (o almeno Android Studio) ha anche un avvertimento per questa situazione:

Variabile utilizzata solo in seguito ritorno e possono essere inline

reports Questa ispezione variabili locali o utilizzate solo nel ritorno molto prossimo o copie esatte di altre variabili. In entrambi i casi è meglio allineare una variabile del genere.


Non credo che le prestazioni è qualcosa di cui preoccuparsi affatto in questa situazione. Detto questo, come menzionato @Clashsoft nel suo commento, la JIT molto probabilmente incorpora la variabile e finirai con lo stesso risultato in entrambi i casi.

+0

Grazie per questo, ha senso e penso che seguirò anche questa regola. – SJ19

+12

In realtà non sono d'accordo con la regola SSLR. Spesso questo rende molto più facile il debug dei metodi, poiché c'è un passaggio nel debugger prima di ritornare dal metodo, dove è possibile osservare il risultato. Il costo per questo è una variabile locale nello stack .... fondamentalmente libero di ripulire. – Jared

+3

Non è necessario un passaggio prima dell'istruzione 'return' per verificare il valore prima che venga restituito durante il debug. Credo che sia più importante avere un codice più pulito rispetto a un altro leggermente più facile da eseguire il debug. Altrimenti avremmo sempre molte variabili locali solo per aiutarci a eseguire il debug di ogni risultato operativo. –

4

I compilatori di solito sono abbastanza intelligenti da ottimizzare questo tipo di cose come appropriato. Vedi data-flow optimizations su Wikipedia.

In questo caso, sarà probabilmente necessario allocare una variabile temporanea per memorizzare il risultato anche se non lo si specifica.

Edit: Clashsoft è di destra circa il compilatore bytecode:

$ cat a.java 
class a { 
    public static int a(int x, int y) { 
    return x/y; 
    } 

    public static int b(int x, int y) { 
    int r = x/y; 
    return r; 
    } 

    public static int c(int x, int y) { 
    final int r = x/y; 
    return r; 
    } 
} 
$ javap -c a 
Compiled from "a.java" 
class a { 
    a(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static int a(int, int); 
    Code: 
     0: iload_0 
     1: iload_1 
     2: idiv 
     3: ireturn 

    public static int b(int, int); 
    Code: 
     0: iload_0 
     1: iload_1 
     2: idiv 
     3: istore_2 
     4: iload_2 
     5: ireturn 

    public static int c(int, int); 
    Code: 
     0: iload_0 
     1: iload_1 
     2: idiv 
     3: istore_2 
     4: iload_2 
     5: ireturn 
} 
+1

Probabilmente il compilatore bytecode Java non prenderà questo a meno che non dichiariate la variabile come 'final', ma dubito fortemente che il compilatore JIT non incorpori la variabile. – Clashsoft

+1

Forse dovresti aggiungere un terzo caso in cui la variabile è dichiarata come 'finale'. –

+0

Grazie. 'finale' o no, fa ancora la differenza. Ora mi chiedo se il JIT se ne prende davvero cura. –

4

Scegli la versione che si pensi sia più leggibile.

Esistono casi legittimi in cui la variabile denominata migliora la leggibilità. Ad esempio

public String encrypt(String plainString) 
{ 
    byte[] plainBytes  = plainString.getBytes(StandardCharsets.UTF_8); 
    byte[] hashPlainBytes = enhash(plainBytes, 4); 
    byte[] encryptedBytes = doAes128(Cipher.ENCRYPT_MODE , hashPlainBytes); 
    String encryptedBase64 = Base64.getEncoder().withoutPadding().encodeToString(encryptedBytes); 
    return encryptedBase64; 
} 

public String decrypt(String encryptedBase64) 
{ 
    byte[] encryptedBytes = Base64.getDecoder().decode(encryptedBase64); 
    byte[] hashPlainBytes = doAes128(Cipher.DECRYPT_MODE , encryptedBytes); 
    byte[] plainBytes  = dehash(hashPlainBytes, 4); 
    String plainString = new String(plainBytes, StandardCharsets.UTF_8); 
    return plainString; 
} 

Ci sono anche casi in cui abbiamo bisogno di una variabile in un tipo diverso dal tipo di ritorno. Questo influenza la conversione e l'inferenza del tipo, facendo una differenza semantica significativa.

Foo foo()   vs.  Foo foo() 
{        { 
            Bar bar = expr; 
    return expr;     return bar; 
}        } 
Problemi correlati