Uso eccessivo della parola chiave "finale" in Java [duplicato]

93

Pur comprendendo cosa viene usata la parola chiave final nel contesto di classi e metodi, nonché l'intento del suo utilizzo per quanto riguarda le variabili; comunque, il progetto su cui ho appena iniziato a lavorare sembra avere un numero eccessivo di loro e sono curioso di sapere la logica che sta dietro.

Il seguente snippet di codice è solo un breve esempio perché non vedo molto punto nella parola chiave final per le variabili key e value :

private <K, V> Collection<V> getValuesForKeys(
    final Map<K, V> map, final Collection<K> keys) 
{
    final Collection<V> values = new ArrayList<V>(keys.size());
    for (final K key : keys) {
        final V value = map.get(key);
        if (value != null) {
            values.add(value);
        }
    }
    return values;
}

Ho letto un po 'l'uso degli articoli che ho trovato tramite Google; tuttavia, il pattern fa davvero cose come aiutare il compilatore a ottimizzare il codice?

    
posta rjzii 04.08.2011 - 20:27
fonte

6 risposte

102

Ci sono molti riferimenti che suggeriscono un liberale use di finale . La specifica del linguaggio Java ha anche una sezione sulle variabili finali . Diverse regole negli strumenti di analisi statica supportano anche questo: PMD ha anche un numero di regole da rilevare quando è possibile utilizzare il finale . Le pagine che ho collegato forniscono un numero di punti su cosa fa final e perché dovresti usarlo liberamente.

Per me, l'uso liberale di final ha compiuto due cose nella maggior parte del codice, e queste sono probabilmente le cose che hanno spinto l'autore del tuo codice ad usarlo:

  1. Rende molto più chiaro l'intento del codice e porta al codice di autocertificazione. L'utilizzo di final impedisce la modifica del valore di un oggetto primitivo o la creazione di un nuovo oggetto e la sovrascrittura di un oggetto esistente. Se non è necessario modificare il valore di una variabile e qualcuno lo fa, l'IDE e / o il compilatore forniranno un avvertimento. Lo sviluppatore deve risolvere il problema o rimuovere esplicitamente il modificatore final dalla variabile. In entrambi i casi, il pensiero è necessario per garantire il raggiungimento del risultato desiderato.

  2. A seconda del codice, serve come suggerimento per il compilatore di abilitare potenzial- mente le ottimizzazioni. Questo non ha nulla a che fare con il tempo di compilazione, ma cosa può fare il compilatore durante la compilazione. Non è nemmeno garantito di fare nulla. Tuttavia, segnalando al compilatore che il valore di questa variabile o l'oggetto a cui fa riferimento questa variabile non cambierà mai potrebbe consentire l'ottimizzazione delle prestazioni.

Ci sono anche altri vantaggi, legati alla concorrenza. Quando applicato a livello di classe o metodo, che ha a che fare con l'assicurazione di ciò che può essere sovrascritto o ereditato. Tuttavia, questi sono oltre lo scopo del tuo esempio di codice. Ancora una volta, gli articoli che ho linkato sono molto più approfonditi su come puoi applicare final .

L'unico modo per essere sicuri del motivo per cui l'autore del codice ha deciso di utilizzare final è trovare l'autore e chiederlo.

    
risposta data 04.08.2011 - 21:08
fonte
30

I principali vantaggi del "finale" nella mia mente sono duplici:

  • Le variabili finali sono "più sicure" delle variabili non finali, perché una volta che sono vincolati non c'è mai una domanda su quale sia il loro stato attuale.
  • A causa di quanto sopra, facendo una variabile finale allevia il programmatore di giocoleria mentale in eccesso - lui / lei non è necessario eseguire la scansione attraverso il codice per vedere se la variabile è cambiata. Questo felice stato di cose sarà familiare a chiunque abbia trascorso del tempo in un contesto linguistico funzionale.

Per quanto riguarda questo specifico esempio, potrebbe darsi che il programmatore abbia colto l'abitudine "finale" e applichi la parola chiave "finale" dappertutto come una cosa ovvia. (Sono scettico sul fatto che la parola chiave finale possa aiutare il compilatore quando si parla di assegnazioni individuali - sicuramente non ha bisogno dell'aiuto per determinare che è stato effettuato un solo incarico?)

Sono dell'opinione che Java lo abbia fatto all'indietro - non ci dovrebbe essere una parola chiave "finale" per le variabili, tutto dovrebbe essere "finale" per impostazione predefinita e se si desidera una variabile mutabile dovresti aggiungere una parola chiave per quello ("var" o alcuni di questi). (Come menzionato da un altro commentatore, scala ha due parole chiave: "val" e "var" per le variabili finali e non finali, rispettivamente - lo prenderò).

    
risposta data 05.08.2011 - 07:56
fonte
11

In Java l'unico posto a mia conoscenza in cui la parola chiave final è richiesta è di rendere una variabile disponibile in modo affidabile per una classe anonima (poiché il compilatore esegue alcuni trucchi sotto le copertine che richiedono che questo il valore non può cambiare).

È - per quanto ne so - un mito che la parola chiave finale consente al compilatore Java di ottimizzare il codice, poiché tutte le ottimizzazioni che importano si verificano nella parte JIT del runtime.

È quindi una questione di gusti. Vi è, tuttavia, un vantaggio molto significativo per l'utilizzo di molte finali, in particolare per rendere il codice più facile per leggere per i futuri manutentori.

Contrassegnare una variabile come final dice al lettore che questa variabile non cambia mai, mai quando viene assegnata. Questo è molto importante quando si legge il codice come sapete quando è necessario conoscere il valore della variabile che è lo stesso come nell'assegnazione iniziale e non è necessario analizzare mentalmente tutto il codice in mezzo per vedere se la variabile viene assegnata di nuovo con qualcos'altro

Inoltre, se vedi che una variabile è non contrassegnata con final , sai che sarà ulteriormente modificato ! Questa è un'informazione estremamente importante che può essere trasmessa al lettore semplicemente manchiando di cinque caratteri.

Tutto ciò che può aiutare il maintainer a fare il suo lavoro più velocemente e in modo più affidabile significa che l'applicazione è più economica da mantenere! In altre parole, final risparmia denaro reale.

Nota: Eclipse ha un'opzione "pulizia del sorgente" che può inserire le finali dove possibile. Ciò potrebbe essere utile sia per scrivere un nuovo codice, sia per mantenere i vecchi (inserire le finali, se alcuni mancano, la variabile viene cambiata dopo l'assegnazione iniziale). Il mio istinto è che questo è ciò che l'autore originale ha scoperto e deciso di usare.

L'argomento è discusso ulteriormente al link

    
risposta data 08.08.2011 - 19:17
fonte
6

Penso che la risposta a questo sia più semplice di quanto suggeriscano altri. Non si tratta di intenti o design. Un bel po 'di tempo fa, era vero che l'aggiunta di final in alcuni punti (in particolare, per metodi e classi) consentiva alla JVM di ottimizzare in modo più aggressivo. Di conseguenza, alcune persone sono impazzite e hanno messo letteralmente la parola ovunque per provare a far andare più velocemente il loro codice.

Devo aggiungere che non è il compilatore, ma la JVM che fa l'ottimizzazione. Inoltre, dubito che mettere la finale su una variabile locale avrebbe mai fatto alcuna differenza per le prestazioni.

Infine, l'utilizzo del finale probabilmente non farebbe molta differenza in questi giorni poiché le ottimizzazioni JVM sono leggermente migliorate.

    
risposta data 04.08.2011 - 23:02
fonte
1

A me sembra che in questo contesto sia utilizzata la parola chiave final per creare una collezione immutable. Le raccolte immutabili sono più semplici e affidabili da usare in programmi che richiedono concorrenza (più thread ).

Ovviamente non è vero. La parola chiave final garantisce solo che il riferimento alla raccolta non possa essere sostituito con un riferimento a una raccolta o null differente.

    
risposta data 04.08.2011 - 21:03
fonte
-2

In una classe, la finale impedisce di essere estesa. Inoltre, impedisce a un utente di sovrascrivere un metodo in una sottoclasse. Lo faresti, sia per proteggere la funzionalità della tua classe che per impedire a qualcuno di manomettere il modo in cui funziona. È anche più efficiente una volta compilato - non so esattamente come al momento, so solo che lo è.

Lo useresti per una variabile come abbreviazione di un valore. Questa è la sostituzione java per il valore del nome #define c / c ++ o la parola chiave const. Il motivo principale per farlo è aumentare la leggibilità e risparmiarti la fatica di dover scrivere un valore più volte nel tuo codice. Soprattutto perché quando vuoi cambiare quel valore, dovresti cambiarlo ovunque. La parola chiave finale garantisce che non potresti cambiare accidentalmente il suo valore in un altro punto del tuo codice.

Sembra eccessivo nel codice che hai postato sopra.

Inoltre, ovviamente è diverso da c ++ nel rispetto del fatto che un valore const non può essere modificato all'interno di un metodo, mentre questo ovviamente è in fase di modifica.

Inoltre, una volta che una variabile è impostata su final, garantisce la sicurezza del thread in quanto è impossibile scrivere sul valore.

    
risposta data 04.08.2011 - 20:38
fonte

Leggi altre domande sui tag