Perché la parola chiave "finale" viene utilizzata così poco nel settore? [chiuso]


14

Da quando ho scoperto i poteri della finalparola chiave in Java qualche anno fa, mi ha aiutato a rendere i miei codici molto più leggibili, poiché le persone possono facilmente vedere quali sono le variabili di sola lettura. Potrebbe anche fornire un piccolo impulso alla JIT, e sebbene sia molto limitata, non può nuocere, specialmente quando si prendono di mira dispositivi embedded come piattaforme Android.

Ma soprattutto, contribuisce a rendere un design più robusto alle modifiche e guida altri committer quando devono modificare la base di codice.

Tuttavia, mentre sfogliavo parte del codice sorgente JDK, non mi sono mai imbattuto in questa parola chiave, né per classi, metodi o variabili. Lo stesso vale per vari sistemi che ho dovuto rivedere.

C'è una ragione? È un paradigma di design comune lasciare tutto mutabile dall'interno?


nelle microottimizzazioni, l'impostazione dei finalcampi ha la stessa semantica della scrittura di un volatilecampo, e quindi leggerli in un secondo momento deve avere una semantica di lettura volatile, questo non è sempre quello che vuoi
maniaco del cricchetto

5
@Ratchet: penso che si tratti più di rendere immutabili le tue classi, come nella programmazione funzionale.
Jonas,

@Kwebble: forse ancora più importante, le singole istanze String sono immutabili.
MatrixFrog,

Risposte:


9

Ho il sospetto che il motivo per cui non lo vedi è perché JDK è progettato per essere esteso (è la base da cui sono basati tutti i tuoi programmi). Non sarebbe affatto raro che il codice dell'applicazione lo usasse. Inoltre, non mi aspetto di vederlo molto nel codice delle librerie (poiché le librerie sono spesso progettate anche per l'estensione).

Prova a dare un'occhiata ad alcuni buoni progetti open source e penso che ne troverai di più.

Contrariamente a ciò che stai vedendo in Java, nel mondo .NET, ho sentito molte volte l'argomento che i clase dovrebbero essere sealed(simili a quelli finali applicati a una classe) per impostazione predefinita e che lo sviluppatore dovrebbe esplicitamente annullare il sigillo esso.


2
Mi riferivo persino a molti membri privati ​​o protetti di alcune classi JDK che sono ovviamente "spawn una volta, mai sovrascrivere" le variabili oggetto. Soprattutto nel pacchetto altalena. Questi sono i candidati perfetti per il "finale", poiché la sostituzione con un puntatore null comporterebbe errori durante l'utilizzo dei componenti.
Aurelien Ribon,

1
@ Aurélien: se ti fa sentire meglio, molte delle classi in .NET Framework sono sigillate, con grande costernazione di alcuni utenti che vorrebbero estendere le classi del framework con le proprie funzionalità. Tuttavia, questa limitazione può essere in qualche modo mitigata utilizzando i metodi di estensione.
Robert Harvey,

1
Penso che ciò riguardi più l'immutabilità che evitare l'estensione. In altre parole, l'uso dei finalcampi on e non dei metodi. Le classi immutabili possono anche essere progettate per essere estese.
Jonas,

15

Il problema con l'utilizzo finalper comunicare che qualcosa è di sola lettura è che funziona davvero solo per tipi primitivi come int, charecc. Tutti gli oggetti in Java vengono effettivamente chiamati utilizzando un (tipo di) puntatore. Di conseguenza, quando usi la finalparola chiave su un oggetto, stai solo dicendo che il riferimento è di sola lettura, l'oggetto stesso è ancora modificabile.

Potrebbe essere stato usato di più se avesse effettivamente reso l'oggetto di sola lettura. In C ++ questo è esattamente cosaconst fa e, di conseguenza, è una parola chiave molto più utile e molto utilizzata.

Un posto in cui uso finalpesantemente la parola chiave è con i parametri per evitare qualsiasi confusione creata da cose come questa:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

In questo esempio sembra ovvio perché questo non funziona ma se someMethod(FancyObject) può derivarne una grande e complicata confusione. Perché non evitarlo?

Fa anche parte degli standard di codifica Sun (o Oracle ora suppongo).


1
Se finalnelle classi dell'API Java è stato più utilizzato , la maggior parte degli oggetti era immutabile come in molte librerie Scala. Quindi la creazione di campi oggetto finalrende la classe immutabile in molti casi. Questo design è già utilizzato in BigDecimale String.
Jonas,

@Jonas Ho letto la domanda per essere più circa il punto 4 nella risposta di schmmd poiché stava dicendo "poiché le persone possono facilmente vedere quali sono le variabili di sola lettura" e ho risposto di conseguenza. Forse avrei dovuto includere quell'ipotesi nella risposta.
Gyan aka Gary Buyn,

Tieni presente che ci sono momenti in cui desideri riassegnare il parametro. Ad esempio, il taglio di un parametro stringa.
Steve Kuo,

@Steve Di solito creo una nuova variabile da assegnare in quella situazione.
Gyan aka Gary Buyn,

1
@Gary, almeno per me, è molto raro che i bug / la confusione siano causati dalla riassegnazione di un parametro. Preferirei di gran lunga avere un codice privo di ingombri e accettare la remota possibilità di riassegnare un parametro che causa un errore. Fai solo attenzione quando scrivi / modifichi il codice.
Steve Kuo,

4

Sono d'accordo che la finalparola chiave migliora la leggibilità. Rende molto più facile capire quando un oggetto è immutabile. Tuttavia, in Java è estremamente dettagliato, in particolare (secondo me) se utilizzato su parametri. Questo non vuol dire che le persone non dovrebbero usarlo perché è prolisso, ma piuttosto non lo usano perché è prolisso.

Qualche altra lingua, come scala, rende molto più semplice fare dichiarazioni finali ( val ). In queste lingue, le dichiarazioni finali possono essere più comuni delle variabili.

Nota che ci sono molti usi diversi della parola chiave finale. Il tuo post riguarda principalmente gli articoli 2 e 3.

  1. Classi finali (JLS 8.1.1.2)
  2. campi finali (JLS 8.3.1.2)
  3. Metodi finali (JLS 8.4.3.3)
  4. Variabili finali (JLS 4.12.4)

2

Per cominciare, le Convenzioni del codice Java ufficiali non favoriscono né vietano l'uso particolare di final. Cioè, gli sviluppatori JDK sono liberi di scegliere il modo che preferiscono.

Non riesco a leggere la loro mente, ma per me, la preferenza sull'uso finalo meno è stata una questione di attenzione. Non importa se ho abbastanza tempo per concentrarmi completamente sul codice o meno .

  • Ad esempio, in uno dei miei progetti potremmo permetterci di spendere mediamente al giorno per circa 100 righe di codice. In questo progetto, ho avuto una chiara percezione di finalcome una spazzatura che oscura solo le cose che sono già espresse abbastanza chiaramente nel codice. Sembra che anche gli sviluppatori JDK rientrino in quella categoria.
     
    D'altra parte, era totalmente opposto in un altro progetto, in cui abbiamo trascorso un'ora in media su 100 righe di codice. Lì, mi sono ritrovato a sparare finalcome una pistola mashine nel mio e nel codice di altri - semplicemente perché era il modo più rapido per rilevare un intento del ragazzo che l'ha scritto prima di me e, allo stesso modo, il modo più veloce per comunicare il mio intento a il ragazzo che lavorerà sul mio codice in seguito.

Potrebbe anche fornire un piccolo impulso alla squadra, e sebbene sia molto limitata, non può nuocere

Ragionare come sopra è scivoloso. L'ottimizzazione prematura può danneggiare; Donald Knuth arriva fino a chiamarlo "la radice di tutti i mali" . Non lasciarti intrappolare. Scrivi un codice stupido .


2

Recentemente ho scoperto la gioia della funzione "Salva azioni" in Eclipse IDE. Posso costringerlo a riformattare il mio codice, inserire @Overrideannotazioni mancanti e fare cose ingegnose come rimuovere le parentesi non necessarie dalle espressioni o inserire finalautomaticamente le parole chiave ovunque ogni volta che premo ctrl + S. Ho attivato alcuni di questi trigger e, ragazzo, aiuta molto!

Si è scoperto che molti di quei trigger si comportano come un rapido controllo di integrità per il mio codice.

  • Intendevo sovrascrivere un metodo ma l'annotazione non veniva visualizzata quando ho colpito ctrl + s? - forse ho rovinato i tipi di parametri da qualche parte!
  • Alcune parentesi sono state rimosse dal codice al momento del salvataggio? - forse quell'espressione logica è troppo difficile per un programmatore per andare in giro rapidamente. Altrimenti, perché dovrei aggiungere prima quelle parentesi?
  • Quel parametro o variabile locale non lo è final. Ha ha di cambiare il suo valore?

Si è scoperto che il minor numero di variabili cambia meno problemi ho al momento del debug. Quante volte hai seguito il valore di una variabile solo per scoprire che in qualche modo cambia da diciamo 5 a 7? "Come diavolo potrebbe essere ?!" ti chiedi e passi le prossime due ore ad entrare e uscire da innumerevoli metodi per scoprire che hai fatto un errore nella tua logica. E per risolverlo devi aggiungere un altro flag, un paio di condizioni e cambiare attentamente alcuni valori qua e là.

Oh, odio il debug! Ogni volta che eseguo il debugger sento che il mio tempo sta per scadere e ho un disperato bisogno di quel tempo per realizzare almeno alcuni dei miei sogni d'infanzia! Al diavolo il debug! finals significa che non ci saranno più cambiamenti di valore misteriosi. Più finals => parti meno fragili nel mio codice => meno bug => più tempo per fare cose buone!

Per quanto riguarda le finalclassi e i metodi non mi interessa davvero. Adoro il polimorfismo. Polimorfismo significa riutilizzo significa meno codice significa meno bug. JVM fa comunque un ottimo lavoro con la devozionalizzazione e il metodo in linea, quindi non vedo un valore nelle possibilità di uccidere per il riutilizzo del codice per vantaggi di prestazione insonni.


Vedere tutte quelle finals nel codice è inizialmente un po 'fonte di distrazione e richiede tempo anche per abituarsi. Alcuni dei miei compagni di squadra sono ancora molto sorpresi nel vedere così tante finalparole chiave. Vorrei che ci fosse un'impostazione nell'IDE per la colorazione della sintassi speciale per questo. Sarei felice di passare a qualche sfumatura di grigio (come le annotazioni) in modo che non si distraggano troppo durante la lettura del codice. Attualmente Eclipse ha un colore separato per returne tutte le altre parole chiave ma non per final.


1
Potresti forse considerare di esaminare linguaggi funzionali come OCaml o F #. Queste lingue tendono a richiedere molto meno debug, uno dei motivi è che tutto è di sola lettura per impostazione predefinita. In poche parole, una volta assegnata, una variabile in un linguaggio funzionale non cambia.
Abel,

1
Sì, lo so e scrivo di tanto in tanto un codice ML di tanto in tanto - è da qui che mi sono ispirato :) Non riguarda il linguaggio che usi ma piuttosto i principi e le tecniche che applichi. Si può andare tutti imperativi con Haskell e donotazione :) Certo, Java non è il miglior linguaggio per scrivere in stile funzionale ma almeno ti permette di scrivere codice robusto, ed è quello che mi interessa davvero.
Andrew Андрей Листочкин,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.