it-swarm.com.de

Verwenden Sie den Modifikator "final", wenn dies in Java

In Java ist es üblich, jede Variable (lokal oder Klasse) als Parameter final zu deklarieren, wenn dies tatsächlich der Fall ist.

Dies macht den Code zwar sehr viel ausführlicher, erleichtert jedoch das Lesen/Erfassen des Codes und verhindert auch Fehler, da die Absicht klar gekennzeichnet ist.

Was denkst du darüber und was folgst du?

187
surajs

Ich denke, das hat alles mit einem guten Coding-Stil zu tun. Natürlich können Sie gute, robuste Programme schreiben, ohne irgendwo viele final - Modifikatoren zu verwenden, aber wenn Sie darüber nachdenken ...

Das Hinzufügen von final zu allen Dingen, die nicht ändern sollten , schränkt einfach die Möglichkeiten ein, die Sie (oder der nächste Programmierer, der an Ihrem Code arbeitet) haben. wird den Gedankenprozess, der zu Ihrem Code geführt hat, falsch interpretieren oder missbrauchen. Zumindest sollte es ein paar Glocken läuten, wenn sie jetzt Ihr bisher unveränderliches Ding ändern wollen.

Anfangs sieht es irgendwie unangenehm aus, viele final - Schlüsselwörter in Ihrem Code zu sehen, aber bald werden Sie aufhören, das Wort selbst zu bemerken, und werden einfach darüber nachdenken -was-wird-sich-von-diesem-Punkt-an-nie-ändern (du kannst es mir abnehmen ;-)

Ich denke, es ist eine gute Übung. Ich benutze es nicht die ganze Zeit, aber wenn ich kann und es Sinn macht, etwas zu beschriften final, mache ich es.

174
Johan Pelgrim

Bessesen von:

  • Endgültige Felder - Wenn Sie Felder als endgültig markieren, werden sie bis zum Ende der Erstellung festgelegt, sodass diese Feldreferenz nicht mehr geändert werden kann. Dies ermöglicht die sichere Veröffentlichung von Feldern und vermeidet die Notwendigkeit einer Synchronisierung bei späteren Lesevorgängen. (Beachten Sie, dass für eine Objektreferenz nur die Feldreferenz unveränderlich ist - Dinge, auf die sich die Objektreferenz bezieht, können sich noch ändern und die Unveränderlichkeit beeinflussen.)
  • Endgültige statische Felder - Obwohl ich jetzt in vielen Fällen, in denen ich statische endgültige Felder verwendet habe, Aufzählungen verwende.

Bedenken Sie, aber verwenden Sie es mit Bedacht:

  • Abschlusskurse - Framework/API-Design ist der einzige Fall, in dem ich es in Betracht ziehe.
  • Endgültige Methoden - Grundsätzlich identisch mit den Endklassen. Wenn Sie Vorlagenmethodenmuster wie "Verrückt" verwenden und "Zeug endgültig" markieren, verlassen Sie sich wahrscheinlich zu sehr auf die Vererbung und nicht genug auf die Delegierung.

Ignoriere es sei denn du fühlst dich anal:

  • Methodenparameter und lokale Variablen - Ich mache das nur selten, weil ich faul bin und finde, dass es den Code durcheinander bringt. Ich gebe voll und ganz zu, dass das Markieren von Parametern und lokalen Variablen, die ich nicht ändern werde, "richtiger" ist. Ich wünschte, es wäre die Standardeinstellung. Aber das ist nicht der Fall und ich finde den Code bei Endrunden überall schwieriger zu verstehen. Wenn ich im Code einer anderen Person bin, ziehe ich sie nicht heraus, aber wenn ich neuen Code schreibe, gebe ich sie nicht ein. Eine Ausnahme ist der Fall, dass Sie etwas Endgültiges markieren müssen, damit Sie darauf zugreifen können es aus einer anonymen inneren Klasse.
182
Alex Miller

Sie müssen wirklich die vollständige Verwendung des endgültigen Schlüsselworts verstehen, bevor Sie es verwenden. Es kann auf Variablen, Felder, Methoden und Klassen angewendet werden und hat unterschiedliche Auswirkungen auf diese

Ich empfehle, den unten verlinkten Artikel zu lesen, um weitere Informationen zu erhalten.

Letztes Wort zum letzten Schlüsselwort

32
HowardSP

Mit dem Modifikator final kann der Compiler insbesondere für Variablen eine allgemein sinnvolle Konvention durchsetzen: Stellen Sie sicher, dass eine (lokale oder Instanz-) Variable genau einmal zugewiesen wird (nicht mehr und nicht weniger). Indem Sie sicherstellen, dass eine Variable definitiv zugewiesen ist, bevor sie verwendet wird, können Sie häufige Fälle von NullPointerException vermeiden:

final FileInputStream in;
if(test)
  in = new FileInputStream("foo.txt");
else
  System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned

Indem Sie verhindern, dass eine Variable mehrmals zugewiesen wird, können Sie das Scoping im Ausland verhindern. An Stelle von:

 String msg = null;
 for(int i = 0; i < 10; i++) {
     msg = "We are at position " + i;
     System.out.println(msg);
 }
 msg = null;

Sie werden aufgefordert, dies zu verwenden:

 for(int i = 0; i < 10; i++) {
     final String msg = "We are at position " + i;
     System.out.println(msg);
 }

Einige Links:

29
Bruno De Fraine

Ich bin ziemlich dogmatisch, wenn es darum geht, jede mögliche Variable final zu deklarieren. Dies umfasst Methodenparameter, lokale Variablen und selten Wertobjektfelder. Ich habe drei Hauptgründe, um endgültige Variablen überall zu deklarieren:

  1. Absichtserklärung: Durch die Deklaration einer endgültigen Variablen erkläre ich, dass diese Variable nur einmal beschrieben werden soll. Es ist ein subtiler Hinweis für andere Entwickler und ein großer Hinweis für den Compiler.
  2. Erzwingen von Einwegvariablen: Ich glaube an die Idee, dass jede Variable nur einen Lebenszweck haben sollte. Indem Sie jeder Variablen nur einen Zweck zuweisen, verringern Sie die Zeit, die erforderlich ist, um den Zweck dieser bestimmten Variablen beim Debuggen zu ermitteln.
  3. Optimierungsmöglichkeiten: Ich weiß, dass der Compiler früher Tricks zur Leistungssteigerung verwendet hat, die sich speziell auf die Unveränderlichkeit einer Variablenreferenz stützten. Ich denke gerne, dass einige dieser alten (oder neuen) Performance-Tricks vom Compiler verwendet werden.

Ich denke jedoch, dass final Klassen und Methoden nicht annähernd so nützlich sind wie final Variablenreferenzen. Wenn das Schlüsselwort final mit diesen Deklarationen verwendet wird, sind dies lediglich Hindernisse für das automatisierte Testen und die Verwendung Ihres Codes auf eine Weise, die Sie nie erwartet hätten.

20
Ryan Ransford

Effective Java hat einen Eintrag mit der Aufschrift "Unveränderliche Objekte bevorzugen". Wenn Sie Felder als endgültig deklarieren, können Sie einige kleine Schritte in diese Richtung unternehmen, aber zu wirklich unveränderlichen Objekten gehört natürlich noch viel mehr.

Wenn Sie wissen, dass Objekte unveränderlich sind, können sie ohne Synchronisationsprobleme zum Lesen für viele Threads/Clients freigegeben werden, und es ist einfacher, über die Ausführung des Programms nachzudenken.

17
Lars Westergren

Ich war noch nie in einer Situation, in der ein endgültiges Schlüsselwort für eine Variable mich davon abgehalten hat, einen Fehler zu machen, und für den Moment halte ich es daher für eine enorme Zeitverschwendung.

Sofern es keinen wirklichen Grund dafür gibt (wie Sie möchten, dass diese Variable endgültig ist), würde ich dies lieber nicht tun, da der Code dadurch weniger lesbar wird.

Wenn Sie jedoch nicht feststellen, dass der Code schwieriger zu lesen oder länger zu schreiben ist, greifen Sie auf jeden Fall zu.

Edit: Als Klarstellung (und als Versuch, Abwärtsstimmen zurückzugewinnen) sage ich nicht, dass Konstanten nicht als endgültig markiert werden sollen.

public String doSomething() {
  final String first = someReallyComplicatedExpressionToGetTheString();
  final String second = anotherReallyComplicatedExpressionToGetAnother();

  return first+second;
}

Es macht Code (meiner Meinung nach) nur schwerer zu lesen.

Es ist auch erwähnenswert, dass all final Sie daran hindert, eine Variable neu zuzuweisen. Dies macht sie nicht unveränderlich oder ähnliches.

10
SCdF

Für Konstanten sollte immer final verwendet werden. Es ist sogar nützlich für kurzlebige Variablen (innerhalb einer einzelnen Methode), wenn die Regeln zum Definieren der Variablen kompliziert sind.

Beispielsweise:

final int foo;
if (a)
    foo = 1;
else if (b)
    foo = 2;
else if (c)
    foo = 3;
if (d)        // Compile error:  forgot the 'else'
    foo = 4;
else
    foo = -1;
8
David Leppik

Klingt wie eines der größten Argumente gegen mit dem letzten Schlüsselwort ist, dass "es unnötig ist", und es "Platz verschwendet".

Wenn wir die vielen Vorteile von "final" anerkennen, auf die viele großartige Beiträge hier hinweisen, und gleichzeitig zugeben, dass es mehr Schreib - und Platz benötigt, würde ich argumentieren, dass Java hätte Variablen durch "final" machen sollen Standard und verlangen, dass die Dinge als "veränderlich" markiert werden, wenn der Codierer dies wünscht.

5
RAY

Ich benutze die ganze Zeit final für Objektattribute.

Das Schlüsselwort final hat eine Sichtbarkeitssemantik, wenn es für Objektattribute verwendet wird. Grundsätzlich erfolgt das Festlegen des Werts eines endgültigen Objektattributs, bevor der Konstruktor zurückkehrt. Dies bedeutet, dass Sie für alle verwenden, solange Sie nicht zulassen, dass die Referenz this aus dem Konstruktor entweicht und Sie final verwenden. ) Sie Attribute, ist Ihr Objekt (unter Java 5 Semantik) garantiert, richtig konstruiert zu werden, und da es auch unveränderlich ist, kann es sicher für andere Threads veröffentlicht werden.

Bei unveränderlichen Objekten geht es nicht nur um Fadensicherheit. Sie machen es auch viel einfacher, über die Zustandsübergänge in Ihrem Programm nachzudenken, da der Raum, in dem sich ändern kann , absichtlich ist und, wenn er konsequent verwendet wird, durch und durch auf die Dinge beschränkt, die ändern sollten .

Ich mache manchmal auch Methoden endgültig, aber nicht so oft. Ich mache selten Klassen endgültig. Ich mache das in der Regel, weil ich es nicht nötig habe. Ich verwende im Allgemeinen nicht viel Vererbung. Ich bevorzuge es, stattdessen Schnittstellen und Objektzusammenstellung zu verwenden - dies bietet sich auch für ein Design an, das sich meiner Meinung nach oft einfacher testen lässt. Wenn Sie nicht mit konkreten Klassen, sondern mit Interfaces codieren, müssen Sie beim Testen mit Frameworks wie jMock nicht die Vererbung verwenden Es ist viel einfacher, Mock-Objekte mit Interfaces zu erstellen als mit konkreten Klassen.

Ich denke, ich sollte die Mehrheit meiner Klassen zum Abschluss bringen, aber ich bin noch nicht in die Gewohnheit gekommen.

5
Chris Vest

Ich muss viel Code für meinen Job lesen. Das Fehlen endgültiger Instanzvariablen ist eines der wichtigsten Dinge, die mich ärgern und das Verstehen des Codes unnötig erschweren. Für mein Geld ist die Endgültigkeit lokaler Variablen eher ein Durcheinander als eine Klarheit. Die Sprache sollte so gestaltet sein, dass sie die Standardsprache ist, aber wir müssen mit dem Fehler leben. Manchmal ist es besonders bei Schleifen und der eindeutigen Zuordnung zu einem if-else-Baum nützlich, aber meistens weist es darauf hin, dass Ihre Methode zu kompliziert ist.

final sollte natürlich für Konstanten verwendet werden und um die Unveränderlichkeit zu erzwingen, aber es gibt eine andere wichtige Verwendung für Methoden.

Wirksames Java weist in diesem Punkt (Punkt 15) auf die Gefahren einer unbeabsichtigten Vererbung hin. Wenn Sie Ihre Klasse nicht für die Vererbung entworfen und dokumentiert haben, kann die Vererbung unerwartete Probleme verursachen (das Element bietet ein gutes Beispiel). Die Empfehlung lautet daher, dass Sie final für jede Klasse und/oder Methode verwenden, von der nicht beabsichtigt war, geerbt zu werden.

Das mag drakonisch erscheinen, macht aber Sinn. Wenn Sie eine Klassenbibliothek zur Verwendung durch andere schreiben, möchten Sie nicht, dass diese von Dingen erbt, die nicht für diese Bibliothek entwickelt wurden. Sie werden sich aus Gründen der Rückkompatibilität auf eine bestimmte Implementierung der Klasse festlegen. Wenn Sie in einem Team codieren, hindert nichts ein anderes Mitglied des Teams daran, das final zu entfernen, wenn dies wirklich erforderlich ist. Aber das Schlüsselwort lässt sie darüber nachdenken, was sie tun, und warnt sie, dass die Klasse, von der sie erben, nicht dafür entwickelt wurde, deshalb sollten sie besonders vorsichtig sein.

3
DJClayworth

Eine weitere Einschränkung besteht darin, dass viele Benutzer "final" so verwechseln, dass sich der Inhalt der Instanzvariablen nicht ändern kann, anstatt dass sich die Referenz nicht ändern kann.

3
Uri

Wenn Sie für jeden Parameter in jeder Methode final eingeben, wird dies sowohl für Codierer als auch für Codeleser zu einer großen Irritation.

Sobald die Irritation über den vernünftigen Wert hinausgeht, wechseln Sie zu Scala, wobei die Argumente standardmäßig endgültig sind.

Oder Sie können immer Code-Styling-Tools verwenden, die dies automatisch für Sie erledigen. Alle IDEs haben sie implementiert oder als Plugins.

2
Oleg Mikheev

Selbst für lokale Variablen bedeutet das Wissen, dass es als endgültig deklariert ist, dass ich mir keine Sorgen machen muss, dass die Referenz später geändert wird. Das bedeutet, dass ich beim Debuggen und beim späteren Anzeigen dieser Variablen sicher bin, dass sie sich auf dasselbe Objekt beziehen. Das ist eine Sache weniger, über die ich mir Sorgen machen muss, wenn ich nach einem Bug suche. Ein Bonus ist, dass, wenn 99% der Variablen als endgültig deklariert werden, die wenigen Variablen, die wirklich variabel sind, besser herausstechen. Außerdem kann der Compiler im Finale weitere mögliche dumme Fehler finden, die sonst möglicherweise unbemerkt bleiben.

2
Diastrophism

Ich programmiere jetzt schon eine Weile und benutze final, wann immer ich kann. Nach einer Weile (für Variablen, Methodenparameter und Klassenattribute) kann ich sagen, dass 90% (oder mehr) meiner Variablen tatsächlich endgültig sind. Ich denke, der Vorteil, KEINE Variablen ändern zu lassen, wenn Sie dies nicht möchten (das habe ich vorher gesehen und es ist manchmal mühsam), zahlt sich für die zusätzliche Eingabe und die zusätzlichen "endgültigen" Schlüsselwörter in Ihrem Code aus.

Abgesehen davon würde ich, wenn ich eine Sprache entwerfen würde, jede Variable endgültig machen, sofern sie nicht durch ein anderes Schlüsselwort geändert wird.

Ich benutze final nicht oft für Klassen und Methoden, dachte ich. Dies ist eine mehr oder weniger komplizierte Entwurfsauswahl, es sei denn, Ihre Klasse ist eine Utility-Klasse (in diesem Fall sollten Sie nur einen privaten Konstruktor haben).

Ich benutze auch Collections.unmodifiable ..., um bei Bedarf nicht modifizierbare Listen zu erstellen.

1
Ravi Wallau

Für Argumente denke ich, dass sie nicht benötigt werden. Die meisten haben die Lesbarkeit verletzt. Das erneute Zuweisen einer Argumentvariablen ist so wahnsinnig dumm, dass ich mir ziemlich sicher sein sollte, dass sie sowieso als Konstanten behandelt werden können.

Die Tatsache, dass Eclipse final red färbt, erleichtert das Erkennen von Variablendeklarationen im Code, von denen ich denke, dass sie die Lesbarkeit die meiste Zeit verbessern.

Ich versuche die Regel durchzusetzen, dass alle Variablen endgültig sein sollten, es gibt keinen extrem gültigen Grund, dies nicht zu tun. Es ist so viel einfacher, die Frage "Was ist diese Variable?" Zu beantworten. frage dich, ob du nur die Initilierung finden und sicher sein musst, dass es das ist.

Tatsächlich werde ich jetzt ein paar Tage nervös, wenn es um nicht endgültige Variablen geht. Es ist wie der Unterschied zwischen einem Messer, das in einem Faden über Ihrem Kopf hängt, oder einem Messer, das Sie in Ihrer Küchenschublade haben ...

Eine letzte Variable ist nur ein guter Weg, um Werte zu kennzeichnen.

Eine nicht endgültige Variable ist an einen Teil eines fehleranfälligen Algorithmus gebunden.

Ein Nizza-Feature ist, dass, wenn die Option besteht, eine Variable für einen Algorithmus zu verwenden, die meiste Zeit stattdessen eine Methode geschrieben werden soll, wodurch der Code normalerweise erheblich verbessert wird.

1
John Nilsson

Ich habe Eclipse so eingerichtet, dass final für alle Felder und Attribute hinzugefügt wird, die nicht geändert wurden. Dies funktioniert hervorragend mit der Eclipse-Funktion "Aktionen speichern", die diese letzten Modifikatoren (unter anderem) beim Speichern der Datei hinzufügt.

Sehr empfehlenswert.

Check out mein Blogpost of Eclipse Save Actions.

1
zvikico

Ich benutze sie nie für lokale Variablen, es hat wenig Sinn für die zusätzliche Ausführlichkeit. Selbst wenn Sie der Meinung sind, dass die Variable nicht neu zugewiesen werden sollte, hat dies keinen Einfluss auf die nächste Person, die den Code ändert, der anders denkt, und da der Code geändert wird, ist möglicherweise ein ursprünglicher Zweck, der ihn endgültig macht, nicht mehr gültig. Wenn es nur der Klarheit halber ist, scheitert es meiner Meinung nach an den negativen Auswirkungen der Ausführlichkeit.

Ähnliches gilt auch für Member-Variablen, da sie mit Ausnahme von Konstanten nur geringen Nutzen bringen.

Es hat auch keinen Einfluss auf die Unveränderlichkeit, da der beste Indikator dafür ist, dass etwas unveränderlich ist, dass es als solches dokumentiert ist und/oder über keine Methoden verfügt, die das Objekt verändern können (dies ist zusammen mit der endgültigen Festlegung der Klasse der einzige Weg, dies zu gewährleisten es ist unveränderlich).

Aber hey, das ist nur meine Meinung :-)

1
Robin

Ich verwende kaum final für Methoden oder Klassen, weil ich es mag, Menschen zu erlauben, sie zu überschreiben.

Ansonsten nutze ich schließlich nur, wenn es sich um einen public/private static final type SOME_CONSTANT; Handelt

1
jjnguy

Final bei Verwendung mit Variablen in Java stellt einen Ersatz für eine Konstante in C++ dar. Wenn also final und static für eine Variable verwendet werden, wird sie unveränderlich. Gleichzeitig machen migrierte C++ - Programmierer ziemlich glücklich. - )

Bei Verwendung mit Referenzvariablen können Sie das Objekt nicht erneut referenzieren, obwohl das Objekt manipuliert werden kann.

Wenn final mit einer Methode verwendet wird, kann die Methode nicht von den Unterklassen überschrieben werden.

Sobald die Verwendung sehr klar ist, sollte es mit Vorsicht angewendet werden. Es kommt hauptsächlich auf das Design an, da die Verwendung der finalen Methode nicht zum Polymorphismus beiträgt.

Man sollte es nur für Variablen verwenden, wenn man verdammt sicher ist, dass der Wert der Variablen niemals geändert wird/werden sollte. Stellen Sie außerdem sicher, dass Sie die von Sun empfohlene Kodierungskonvention einhalten. Beispiel: final int COLOR_RED = 1; (Großbuchstaben durch Unterstrich getrennt)

Verwenden Sie eine Referenzvariable nur, wenn Sie eine unveränderliche Referenz auf ein bestimmtes Objekt benötigen.

In Bezug auf den Lesbarkeitsteil ist darauf hinzuweisen, dass Kommentare bei der Verwendung des Modifikators final eine sehr wichtige Rolle spielen.

1
Omnipotent

Das Markieren der Klasse final kann auch dazu führen, dass einige Methodenbindungen zur Kompilierungszeit statt zur Laufzeit ausgeführt werden. Betrachten Sie "v2.foo ()" weiter unten - der Compiler weiß, dass B keine Unterklasse haben kann, daher kann foo () nicht überschrieben werden, sodass die aufzurufende Implementierung zur Kompilierungszeit bekannt ist. Wenn Klasse B NICHT als endgültig markiert ist, ist es möglich, dass der tatsächliche Typ von v2 eine Klasse ist, die B erweitert und foo () überschreibt.

class A {
    void foo() {
        //do something
    }
}
final class B extends A {
    void foo() {
    }
}
class Test {
    public void t(A v1, B v2) {
        v1.foo();
        v2.foo();
    }
}
0
Eugene

Die Verwendung anonymer lokaler Klassen für Ereignis-Listener und dergleichen ist in Java ein verbreitetes Muster. Das Schlüsselwort final wird am häufigsten verwendet, um sicherzustellen, dass der gerade Listener auf Variablen im Gültigkeitsbereich zugreifen kann.

Wenn Sie jedoch feststellen, dass Sie viele abschließende Anweisungen in Ihren Code einfügen müssen. Das könnte ein guter Hinweis sein, dass Sie etwas falsch machen.

Der Artikel oben gibt dieses Beispiel:

public void doSomething(int i, int j) {
    final int n = i + j; // must be declared final

    Comparator comp = new Comparator() {
        public int compare(Object left, Object right) {
            return n; // return copy of a local variable
        }
    };
}
0
Hans Sjunnesson

Ich benutze es für Konstanten innerhalb und außerhalb von Methoden.

Ich verwende es nur manchmal für Methoden, weil ich nicht weiß, ob eine Unterklasse eine bestimmte Methode NICHT überschreiben möchte (aus welchen Gründen auch immer).

Soweit Klassen, nur für einige Infrastrukturklassen, habe ich letzte Klasse verwendet.

IntelliJ IDEA warnt Sie, wenn ein Funktionsparameter in eine Funktion geschrieben wird. Daher verwende ich final nicht mehr für Funktionsargumente. Ich sehe sie nicht in Java Laufzeitbibliothek auch.

0
anjanb