wollte fragen was ihr davon hält, IMMER final zu verwenden, falls die instanz nachträglich nicht mehr erneut zugewisen wird. also nicht nur für (public static) member-konstanten des typs int oder String (oder andere "einfache" datentypen), wie man das meist sieht...
hat das einen einfluss auf die performance? wenn ja in welcher hinsicht?
fürs Programm ist es ohne Negativmerkmale uneingeschränkt gut (edi: bzw. auch nicht, siehe Folgeantworten),
für den Quelltext ist es je nach Belieben ebenso gut (wichtige Information zum Verständnis der Variablen) bis hin zu störend da unleserlich,
außerdem können unter lauter 'normal finalen' Variablen die 'zwingend besonders wichtigen finalen' Variablen untergehen (weniger Information?),
außerdem zusätzlicher Schreibaufwand wenn man nicht eh daran gewöhnt ist
wollte fragen was ihr davon hält, IMMER final zu verwenden, falls die instanz nachträglich nicht mehr erneut zugewisen wird. also nicht nur für (public static) member-konstanten des typs int oder String (oder andere "einfache" datentypen), wie man das meist sieht...
etwas einfach pauschal zu machen ist nie gut. Da kann man auch sagen: "ich schließe die Augen, trete voll aufs Gas und da ich nichts sehe, passiert mir auch nichts". Man muss sich immer bewusst sein, was man gerade macht. Weiterhin sollte man den Sinn, Zweck oder Still der Vorgehensweise anderen erklären oder verständlich aufschreiben können. Wer ohne größere Ahnung programmiert, dem hilft auch kein final alle paar Zeilen.
Der Modifier final hat bei Attributen noch einen Nebeneffekt. Der JIT-Compiler ist bei final Attributen etwas eingeschränkt in Bezug auf die Möglichkeiten die Reihenfolgen der Operationen umzustellen. Das kann durchaus geringfügig negative Auswirkungen auf die Performance haben. Speziell bei privaten Attributen wo der JIT selbst erkennen kann ob ein Feld sich jenseits vom Konstruktor ändern kann dürfte es wenn überhaupt ein Unterschied vorhanden ist eher einen absolut minimalen Nachteil geben.
Die Unterschiede sind im Endeffekt aber zu gering als das man darauf Rücksicht nehmen sollte.
Kurz gesagt: final sollte man einfach dann verwenden wenn man der Meinung ist das sich der Wert eines Attributes innerhalb einer Instanz niemals ändern soll.
@slaterb: "außerdem können unter lauter 'normal finalen' Variablen die 'zwingend besonders wichtigen finalen' Variablen untergehen"
...ja, das hat definitiv was! die 'zwingend besonders wichtigen' könnte man in diesem fall aber z.b. gross schreiben.
@slawaweis: "etwas einfach pauschal zu machen ist nie gut."
-> der grund dafür ist, das alle variablen, welche nachträglich nicht erneut zugewiesen werden, nicht erneut zugewiesen werden können. (also eine art restriktion...)
Zitat von Joshua Bloch: "final is the new private". Laut ihm sollte man es immer und überall verwenden, wenn kein zwingender Grund besteht, es nicht zu tun (siehe entsprechende JavaOne-Slides). (Allerdings mache ich das auch nicht, es ist etwas unübersichtlicher und noch etwas ungewohnt, weil es rein teschnisch eigentlich nicht soo viel bringt - ist eher eine Stilfrage)
Ich habe bei mir in Eclipse die Save Action Add final modifier to private fields immer an. Da wird jede Klassenvariable, die nur im Konstruktor gesetzt und sonst nur gelesen wird automatisch auf final gesetzt. Ich finde das sehr nützlich. Je größer die Klasse, desto größer der Nutzen. Bei lokalen Variablen benutze ich es nicht.
Bei private Fields weniger. Ich weiß nicht mehr, ob sich das auch darauf bezog (in den Folien), aber eigentlich sollte man meistens auch bei Methodenparametern "final" dazuschreiben können. Bei "vielen" Parametern wäre das unübersichtlicher, aber wohl nicht sooo dramatisch (zumal eine Methode ja eh nicht "viele" Parameter haben sollte )
Tja, manche wollen das wohl. Für mich sind Argumente lokale Variablen wie alle anderen auch, darum modifiziere ich die auch, wenn es mir hilft. Das passiert allerdings enorm selten.
Es gibt auch entsprechende Save actions dafür. Ich bleibe dennoch nur bei Klassenvariablen.
@musiKk: "...die nur im Konstruktor gesetzt und sonst nur gelesen wird..."
-> ja, diesen "trick" kenne ich auch, die membervariable einfach in der art String str1; statt String str1 = null; setzen...
"Für mich sind Argumente lokale Variablen wie alle anderen auch, darum modifiziere ich die auch, wenn es mir hilft. Das passiert allerdings enorm selten."
-> weil das eben enorm selten passiert, mach ich grundsätzlich argumentvariablen auch final... GENAU DORT hat man am wenigsten probleme, sprich nachträgliches entfernen des final, z.b. auf grund einer fehlüberlegung...
Ich persönlich mache mittlerweile auch wo immer es geht Membervariablen, Methodenparameter und auch Lokale Variablen final, einfach weil es das lesen etwas einfacher macht (man kann sich eben darauf verlassen, dass sich der Wert nach der ersten Zuweisung nicht mehr ändert außer eben die Klasse ist Mutable und es wird ein Setter aufgerufen.)
Durch den Blogpost überlege ich jedoch auf final in Methodenparametern zu verzichten, weil es die Signatur doch recht lang macht und nur minimal hilft.
Ich blicke nicht ganz durch, was der Autor des Blogs uns da mitteilen will.
Ich mache zumindest alles so final wie möglich. Wenn man im Verlauf des Codens deswegen einen Compiler-Fehler bekommt, kann man sich nochmal überlegen, ob man die Variable wirklich neu zuweisen muss.
...
comes with a little value. It could help you in cases when you forget "this", or try to assign something to a parameter. Both errors would be immediately visible in the first unit or integration test.
...
I forget sometimes the "this." keyword what immediately results in an IDE (NetBeans / IntelliJ in my case) warning.
I cannot remember any case of an attempt to assign something to a parameter...
...
Did you ever had trouble with non-final method parameters?
Techniken/Methoden/Angewohnheiten um solche Fehler zu finden gibt es mehrere, das final Schlüsselwort ist eines davon.
Leute die keine Unit- und Integrationstests dafür aber sehr lange Methoden schreiben und deren IDE nicht warnt wenn man einem Parameter etwas zuweist bzw. das this vergisst, sollten final beibehalten, so hab ich ihn verstanden.
Das final ist vor allem für Anfänger gut imho, schaden wird es andern auch nicht, wenn man mal von dem "mehr" an Quelltext absieht.
Unit-/Integrationstests ersetzt es nicht, umgekehrt können aber solche Tests das final "ersetzen", zumindest was das aufspüren von fehlern angeht.
Es erhöht die Störanfälligkeit und verhindert eher ungewöhnliche Fehler? ???:L
Den Titel verstehe ich nun auch nicht. Für mich ist nicht wirklich erkennbar, ob er sich für oder gegen final method parameters ausspricht.
Also entweder bin ich des Englischen nicht so mächtig oder er, oder er kann sich nicht richtig ausdrücken.
Generell ist final sinnvoll, aber für Methodenparameter NICHT!
Seinere Meinung nach erschweren sie das lesen von Quellcode ("increases the noise") und bringen dabei kaum Vorteile ("and prevents rather esoteric errors"), da lediglich zwei Fehler aufgedeckt werden:
Fehler 1)
Java:
publicvoidfoo(int bar){
bar =1;// das ist zwar ok, sollte man aber nicht machen}
Dieser tritt seiner Meinung nach, jedoch eh so gut wie nie auf ("I cannot remember any case of an attempt to assign something to a parameter...")
Was jedoch in vielen IDEs bereits als Warnung markiert wird ("I forget sometimes the "this." keyword what immediately results in an IDE (NetBeans / IntelliJ in my case) warning.")
Seiner Meinung nach, wären diese beiden Fehler jedoch auch mit Test zu erkennen ("Both errors would be immediately visible in the first unit or integration test.").
Zu deinem Nachtrag:
Durchaus häufig anzutreffen und meiner Meinung nach auch vollkommen in Ordnung: Long.toString(count) würde natürlich auch gehen.
für mich ist dieser Titel, Artikel und dessen Aussage schon klar bzw. eindeutig: gegen final
"final" ist nicht nötig, Unit-/Integrationstests würden diese Fehler auch aufdecken, dazu kommt, dass die meisten prof. Javaentwickler so gut sind dass ihnen diese fehler nicht passieren
Bien argumentiert gerne gegen Dinge die wir aus Gewohnheit/Konvention machen und stellt sie auf den Prüfstand, seine Meinung muss man ncht teilen, er startet gerne Diskussionen, dabei kommen pro und contra Argumente zum Vorschein.
Die Konvention/Empfehlung final zu verweden ist sehr alt (für Javaverhältnisse), damals war es nicht üblich viel zu automatisiert testen, TDD war nichtmal theoretisch vorhanden, Fehler die der Compiler finden konnte waren die "besten" Fehler.
Heute dagegen ist die Sache etwas anders, wenn man nahe 80-90% des Codes mit Unittests abdeckt und dann nochmal so viel mit Integrationstests, kann man sich das eine oder andere Sprachmittel zur statischen Prüfung sparen.
Gnaz zu schweigen von der dynmk die zB. durch DI Frameworks gegeben ist, da fliegt mal schnell eine Exception zur Laufzeit, den Fehler kann der compiler gar nicht mehr finden.
Wie gesagt, würde es heute für jeden Anfänger verpflichtend machen final zu verwenden (denn Anfänger arbeiten nicht so häufig mit autom. Unittests).
Okay, er will also sagen, dass final method parameters (fast) keinen Mehrwert haben. Als Gegenargument bringt er jedoch nur, dass die readability leidet. Bei den sechs Zeichen mehr, die man dann pro Parameter hat, kann ich das auch nicht unbedingt nachvollziehen.
"final" ist nicht nötig, Unit-/Integrationstests würden diese Fehler auch aufdecken, dazu kommt, dass die meisten prof. Javaentwickler so gut sind dass ihnen diese fehler nicht passieren
Okay, er will also sagen, dass final method parameters (fast) keinen Mehrwert haben. Als Gegenargument bringt er jedoch nur, dass die readability leidet. Bei den sechs Zeichen mehr, die man dann pro Parameter hat, kann ich das auch nicht unbedingt nachvollziehen.
Ja, fast keinen mehrwert, wenn man autom. Tests hat.
6 Zeichen pro Parameter, bei 2 Parametern sind das schon 12
Mag nicht viel sein, aber Lesbarkeit ist in den letzten jahren als wichtig eingestuft worden.
Das ist ja der Grund weswegen er fragt, wie oft einem schon solche einfachen fehler unterlaufen sind, ohne final.
Falls die Antwort "gar nicht" lautet, kann man sich selber denken welchen Mehrwert final dann hatte.
Auch prof. Entwickler machen fehler, dafür braucht man tests, die Frage ist eben, ob prof. Entwickler Anfängerfehler machen.
Falls man sowieso Tests hat, sinkt der Mehrwert von final nochmals.
das der Mehrwert beim Schreiben nicht allzu groß ist, dem mag ich mich ja noch anschließen. Imho liegt der Mehrwert aber gerade in der erhöhten Lesbarkeit. Wenn ich den Quellcode eines Fremden lese, dann kann ich nicht wissen, an welche Konventionen er sich hält. Und drauf verlassen kann ich mich schon gar nicht. Ich muss beim Lesen der Methode also ständig aufpassen ob Methodenparameter nicht doch irgendwo als lokale Variablen genutzt wurden. Beim Einsatz von final muss ich zwar 5+1 Zeichen mehr lesen (das schaffe ich gerade noch so ) erhalte aber als Mehrwert das Wissen, dass diese Parameter wirklich final sind. Solche Überraschungen wie
mit angezogener Handbremse ist es auch sicher zu fahren ...
@Thema - wenn ich Quelltext schreibe, so schreibe ich diesen um die 3 bis 5 Mal um bzw. neu. Man kann gar nicht von vornherein wissen, was final sein muss, was nicht. Außerdem kann am Ende das Programm auf Leistung optimiert werden und da werden solche sicheren Sachen sowieso über den Haufen geworfen.
Weiterhin schützt final nicht vor schlechtem Code. Im schlechtesten Fall sorgt es für solche Workarounds:
Java:
publicclass XYZ
{protectedfinalintA;// Version 1.0protectedint A_;// Version 2.0}
wo man anstatt das final zu entfernen, einfach eine neue mutable Variable als Ersatz einführt. Ich habe schon einiges an Quelltext gesehen, wo wegen verschiedenen Problemen und schlechter Dokumentation, die neuen Entwickler neuen Code einfach an den alten "dranheften", weil sie das vorhandene nicht verstehen oder Angst haben, alles kaputt zu machen.
Auch in der Funktionsdeklaration bringt es nur scheinbare Sicherheit, Beispiel:
Java:
publicvoidfunc(finalint x){// Workaroundint xx = x;// ab hier wird xx als Alias zu x verwendet// ... 100 Zeilen Code ...// der Entwickler geht an dieser Stelle davon aus, dass xx == x ist,// und sieht nicht nach, ob xx nicht irgendwo verändert wurde.}
Aus diesem Grund sage ich ja auch, man muss sich immer bewusst sein, was man gerade macht. Es gibt spezielle Programme, die den Code überprüfen und potentielle Problemstellen melden. Die finden auch mehr, als nur das fehlende final.
Der Einsatz von final ist nicht verkehrt, nur sich blind darauf zu verlassen sollte man nicht.
> // der Entwickler geht an dieser Stelle davon aus, dass xx == x ist
das ist nicht plausibel, wieso wurde dann überhaupt eine zweite Variable eingeführt?
dein ganzes Posting beschreibt allgemein Probleme zwischen neuen Programmiern, alten Code nicht ändern, schlechte Doku usw.,
überzeugend speziell auf final bezogen ist für davon wenig bis nichts
zu Version 1.0 + Version 2.0:
aber was soll der erste Programmierer daran machen, seine Variable nicht als final deklarieren, obwohl es nötig und sinnvoll ist?!
> // der Entwickler geht an dieser Stelle davon aus, dass xx == x ist
das ist nicht plausibel, wieso wurde dann überhaupt eine zweite Variable eingeführt?
dein ganzes Posting beschreibt allgemein Probleme zwischen neuen Programmiern, alten Code nicht ändern, schlechte Doku usw.,
überzeugend speziell auf final bezogen ist für davon wenig bis nichts
zu Version 1.0 + Version 2.0:
aber was soll der erste Programmierer daran machen, seine Variable nicht als final deklarieren, obwohl es nötig und sinnvoll ist?!
wann ist es denn nötig und sinnvoll? Wenn man davon ausgeht, dass ohne das final die Variable sofort falsch verwendet wird, hat man ganz andere Probleme.
Sagt wer?
Sorry, aber zu sagen dass dein Vergleich hinkt wäre eine Untertreibung
Klar ist defensiv Programmieren pauschal gesagt eine gute Sache.
wenn ich Quelltext schreibe, so schreibe ich diesen um die 3 bis 5 Mal um bzw. neu. Man kann gar nicht von vornherein wissen, was final sein muss, was nicht.
Wirklich? Bei Methodenparametern?
Diese sind bei mir zu 99,9% immer final, in JavaBeans zu 100%, ein final "wegrefactoren" ist nicht aufwändig, und der compiler hilft dabei.
Weiterhin schützt final nicht vor schlechtem Code. Im schlechtesten Fall sorgt es für solche Workarounds:
Bei dieser "scheinbaren Sicherheit" geht es schlicht darum, dass einfache fehler garantiert nicht vorkommen können.
Java:
setXxx(finalint xxx){
xxx = xxx;}
... wird garantiert nicht compiliert, das hier dagegen schon:
Java:
setXxx(int xxx){
xxx = xxx;}
Letzeres sollte zumindest eine Warnung produzieren, aber wer garantiert dass diese gelesen wird in einem Legacyprojekt das entweder 10000 Warnings hat, oder besser, alle warnings abgeschaltet wurden "weil es zuviele gab"?
final ist keine Wunderwaffe sondern kann helfen Flüchtigkeitsfehler zu vermeiden, nicht mehr und nicht weniger.
Wenn ich meine Setter zB. von Eclipse gerenieren lasse, kann ich das final weglassen.
Da wir hier aber im Anfängerforum sind, ist final auf jedenfall eine gute Sache
wann ist es denn nötig und sinnvoll? Wenn man davon ausgeht, dass ohne das final die Variable sofort falsch verwendet wird, hat man ganz andere Probleme.
ich stimme zu insofern als dass ich selber auch nie final einsetze, außer bei public static final-Konstanten, anonymen inneren Klassen,
und Parameter-Zuweisung bemeckert der Compiler
aber final generell anzuzweifeln ist ja etwas herbe,
wenn man keine Fehler selber einbaut, dann kann man auch auf private verzichten usw.,
final minimiert die Möglichkeiten in einer normalerweise uneingeschränkten Sprache, weist direkt auf Fehler hin,
an anderer Stelle wurde festgelegt 'das nicht machen', das ist doch ein zu begrüßendes Konzept,
besser z.B. als alle Kommentare und JavaDoc, die ohne Lesen und gewisse Warning-Einstellungen in IDEs überhaupt keine Auswirkung haben
wenn jemand
Java:
// Version 1.0privateString geheim;privateStringgetGeheim(){// getter nur damit niemand noch einen schreibtreturnthis.geheim;}// Version 2.0publicStringgetGeheim2(){// brauch ich aberreturnthis.geheim;}
programmiert, dann ist das doch auch nicht die Schuld von private..
ich bin nicht generell gegen das final. Ich bin dagegen, final einfach pauschal überall dranzuhängen, wo es nur geht. Das ist eine falsche Sicherheit, welche die Weiterentwicklung erschweren kann. Besonders in Kombination mit public wurde damit schon viel schlechter Code produziert (J2ME ausgeschlossen). Ich habe es noch nie bei der Methodendeklaration verwendet und hatte auch keine größeren Probleme damit. Bestimmte typische Fehlerquellen kann auch eine IDE melden oder ein Programm, welches den Code überprüft. Im guten Code wird das die Ausnahme bleiben, das final überall ist nicht notwendig. Im schlechten Code hilft auch ein final alle paar Zeilen nicht viel.
ich habe schon defensive Programmierung erlebt. Jede Methode hatte mindestens an die 5 verschiedene harte Exceptions, jedes auch so kleine Konzept hatte seine eigene Klasse (wo Kostanten oder Enums ausgereicht hätten) mit tiefer Ableitungshierarchie und fast alle Membervariablen private waren. Das Arbeiten mit so einem defensiven Code ist eine Zumutung und es schützt trotzdem nicht vor Fehlern.
Für mich dreht sich die Diskussion gerade noch zu einseitig um das final an sich. Ich finde das zu engstirnig, da es mMn nicht direkt darauf ankommt welche Fehler ich dadurch vermeiden kann oder sogar erzeuge, sondern welchen tieferen Sinn man mit final - oder besser Unveränderlichkeit - erreichen will, bzw. welches Programmierkonzept sich dahinter verbirgt.
Die entscheidende Frage ist doch: Warum sollte sich eine Variable ändern?
Code:
var x = ...
var xChanged = change(x)
// oder
var x = ...
x = change(x)
Wenn eine Variable ihren Wert ändert und dieser neuen Wert wieder der selben Variablen zugewiesen wird, dann ist dieser Wert ja nicht mehr der Selbe - also ist eine Zuweisung schon von Grund auf unlogisch.
Wenn ich aber einen neuen Wert auch einer neuen Variablen zuweise, dann hab ich die Möglichkeit damit auszudrücken, dass sich ein Wert eben geändert hat (ein Nebeneffekt ist, dass ich auch noch die Möglichkeit habe dieser neuen Variablen einen Namen zu geben, der viel besser aussagen kann was sie beinhaltet als es der Name der alten Variable je tun könnte).
Ich hab festgestellt, dass mein Code bei weitem lesbarer geworden ist seit ich mich an die Unveränderlichkeit halte. Die Methoden wurden allgemein kürzer und seiteneffektfreier was viel mehr zur Verständlichkeit des Codes bei trägt als ein paar entfernte finals. Weiter ist mir die Gewissheit wichtig, dass eine Methode bei jedem Eingabewert einen dazugehörigen Ausgangswert liefert. Dabei darf es keine Rolle spielen wie oft ich die Methode aufrufe - sie muss immer den gleichen Ausgangswert zurück liefern wenn der selbe Eingangswert eingegeben wurde.
Diese Gewissheit erhalte ich nicht wenn jemand final verwendet - ich erhalte sie deshalb weil ich erkennen kann, dass er dem Konzept der Unveränderlichkeit folgt. Das gibt mir auch die Möglichkeit das final irgendwann einfach zu überlesen - ich weiß ja dass es da ist, aber es stört mich nicht.
Das kann man mit dem Blinken beim Autofahren vergleichen: Wenn ich bei jedem Streifenwechsel oder Abbiegevorgang noch überlegen muss ob ein Blinken erforderlich ist oder ob man es auch weglassen kann, dann bedeutet das einen Aufwand. Wenn ich aber einfach immer Blinke, dann geschieht das irgendwann automatisch - ich muss dann nicht mehr dran denken und weiß trotzdem, dass es passiert.
Wenn beim Autofahren das Konzept das Blinken ist, dann ist das Konzept bei final eben die Unveränderlichkeit. Ob
Code:
x = x
oder andere Dinge durch final ermöglicht oder verhindert werden ist mir dabei total egal - das sind Nebeneffekte mit denen ich leben kann wenn das Gesamtkonzept (der "tiefere Sinn") passt.
Man kann dabei die Umsetzung eines Konzeptes in einer bestimmten Programmiersprache bemängeln - in Java hat man z.B. bei Schleifenvariablen groß keine Möglichkeiten diese unveränderlich zu machen. Tailrekursive Methoden kann der Compiler nicht optimieren und Closures, mit denen man die veränderlichen Objekte "verstecken" kann, gibt es noch nicht.
Der Text ist jetzt vllt. ein bisschen lang geworden und ich bin mir nicht mal sicher ob ich darin ausdrücken konnte was ich eigentlich sagen wollte.
@Slawa
Sorry, aber das sind alles Probleme schlechter Entwickler. Dagegen ist kein Kraut gewachsen. Außerdem fährt man mit angezogener Handbremse nicht sicher sondern ist eine Gefahr für sich und andere (diese Analogie passt auch wieder schön auf die schlechten Entwickler... *G*)
Die Frage ist doch eigentlich: setze ich alles final und denke an den Stellen darüber nach, wo ich es nicht brauche oder setze ich nichts final und setze es nur an den Stellen, an denen ich es muss (z.B. wenn aus einer inneren Klasse nach außen gegriffen wird).
In beiden Fällen muss ich entweder einen quasi pauschalen Ansatz verwenden oder mir bei jeder Variable erst mal Gedanken machen. Dann finde ich den pauschalen "final" Ansatz besser. Er ist nicht wirklich unleserlicher und ist definitiv ein Hint an den Laufzeitcompiler und er erzeugt selbst dokumentierenden Code. Die IDE erinnert mich daran, dass ich gerade versuche eine finale Variable zu ändern und ich überlege, ob es das ist was ich wollte (in der Regel ist es das, und das final verschwindet). Das sind in der Regel die typischen Scoping-Probleme beim Aufräumen von Ressourcen.
Wenn du also (nicht nur hier) keinen pauschalen Ansatz als Initiallösung fährst, bist du ständig damit beschäftigt dir über Pillepalle Gedanken zu machen. Also sollte man den günstiger Pauschalansatz verwenden und immer ein wenig mitdenken, das ist wohl die beste Lösung.