Warum wird das Schlüsselwort "final" in der Branche so selten verwendet? [geschlossen]


14

Seit ich vor finalein paar Jahren die Möglichkeiten des Schlüsselworts in Java entdeckt habe, konnte ich meine Codes viel besser lesen, da die Benutzer leicht erkennen können, was schreibgeschützte Variablen sind. Es kann auch die JIT ein wenig ankurbeln, und obwohl es sich um eine sehr eingeschränkte handelt, kann es nicht schaden, insbesondere wenn es auf eingebettete Geräte wie Android-Plattformen abzielt.

Vor allem aber trägt es dazu bei, ein Design widerstandsfähiger gegen Änderungen zu machen und andere Committer bei der Änderung der Codebasis zu unterstützen.

Beim Durchsuchen eines Teils des JDK-Quellcodes bin ich jedoch nie auf dieses Schlüsselwort gestoßen, weder für Klassen, Methoden noch für Variablen. Gleiches gilt für verschiedene Systeme, die ich überprüfen musste.

Gibt es einen Grund? Ist es ein gängiges Design-Paradigma, alles von innen wandelbar zu lassen?


in der Mikro - Optimierungen, das Setzen von finalFeldern hat die gleiche Semantik wie ein volatileSchreibfeld, und dann muss das Lesen später flüchtige Lese Semantik haben, das ist nicht immer das, was Sie wollen
Ratsche Freak

5
@ratchet: Ich denke, es geht eher darum, Ihre Klassen unveränderlich zu machen, wie bei der funktionalen Programmierung.
Jonas

@Kwebble: Vielleicht noch wichtiger ist, dass einzelne String- Instanzen unveränderlich sind.
MatrixFrog

Antworten:


9

Ich vermute, der Grund, warum Sie es nicht sehen, ist, dass das JDK für die Erweiterung ausgelegt ist (es ist die Basis, auf der alle Ihre Programme aufbauen). Es ist nicht ungewöhnlich, dass Anwendungscode davon Gebrauch macht. Ich würde auch nicht erwarten, viel davon im Bibliothekscode zu sehen (da Bibliotheken oft auch für Erweiterungen ausgelegt sind).

Werfen Sie einen Blick auf einige gute Open Source-Projekte und ich denke, Sie werden mehr finden.

Im Gegensatz zu dem, was Sie in Java in der .NET-Welt sehen, habe ich oft das Argument gehört, dass Klassen standardmäßig sealed(ähnlich wie final auf eine Klasse angewendet) sein sollten und dass der Entwickler die Versiegelung explizit aufheben sollte es.


2
Ich bezog mich sogar auf viele private oder geschützte Mitglieder einiger JDK-Klassen, die offensichtlich Objektvariablen "einmal erzeugen, niemals überschreiben". Besonders im Swing-Paket. Dies sind perfekte Kandidaten für 'final', da das Ersetzen durch einen Nullzeiger zu Fehlern bei der Verwendung der Komponenten führen würde.
Aurelien Ribon

1
@ Aurélien: Wenn Sie sich besser fühlen, sind viele der Klassen in .NET Framework versiegelt, sehr zur Bestürzung einiger Benutzer, die die Framework-Klassen mit ihrer eigenen Funktionalität erweitern möchten. Diese Einschränkung kann jedoch durch die Verwendung von Erweiterungsmethoden
Robert Harvey

1
Ich denke, hier geht es mehr um Unveränderlichkeit als darum, eine Verlängerung zu vermeiden. Mit anderen Worten, die Verwendung von finalFeldern und nicht von Methoden. Unveränderliche Klassen können auch erweitert werden.
Jonas

15

Das Problem bei der Verwendung , finaldass etwas zu vermitteln , ist schreibgeschützt ist , dass es wirklich nur für primitive Typen funktioniert wie int, charetc. Alles in Java - Objekten werden mit einem (Art) Zeiger tatsächlich bezeichnet. Wenn Sie das finalSchlüsselwort für ein Objekt verwenden, wird daher nur gesagt, dass die Referenz schreibgeschützt ist und das Objekt selbst noch veränderbar ist.

Es könnte mehr verwendet worden sein, wenn das Objekt tatsächlich schreibgeschützt wäre. In C ++ ist das genau das, was es consttut, und als Ergebnis ist es ein viel nützlicheres und am häufigsten verwendetes Schlüsselwort.

Ein Bereich, in dem ich das finalSchlüsselwort häufig verwende, sind Parameter, um Verwirrungen zu vermeiden, die durch Folgendes verursacht werden:

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 diesem Beispiel scheint es offensichtlich, warum dies nicht funktioniert, aber wenn someMethod(FancyObject)es groß und kompliziert ist, kann es zu Verwirrung kommen. Warum vermeiden wir es nicht?

Es ist auch Teil der Sun- (oder Oracle-) Codierungsstandards.


1
Wenn finaldie Java-API-Klassen häufiger verwendet wurden , waren die meisten Objekte wie bei vielen Scala-Bibliotheken unveränderlich. Wenn Sie dann Objektfelder erstellen, finalwird die Klasse in vielen Fällen unveränderlich. Dieses Design wird bereits in BigDecimalund verwendet String.
Jonas

@Jonas Ich habe die Frage gelesen, um mehr über Punkt 4 in der Antwort von schmmd zu erfahren, da er sagte, "da die Leute leicht sehen können, was schreibgeschützte Variablen sind" und entsprechend beantwortet. Vielleicht hätte ich diese Annahme in die Antwort aufnehmen sollen.
Gyan aka Gary Buyn

Denken Sie daran, dass es eine gewisse Zeit gibt, in der Sie den Parameter neu zuweisen möchten. Als Beispiel wird ein String-Parameter abgeschnitten.
Steve Kuo

@Steve Normalerweise erstelle ich eine neue Variable, die in dieser Situation zugewiesen wird.
Gyan aka Gary Buyn

1
@ Gary, zumindest für mich ist es sehr selten, dass Fehler / Verwirrung durch die Neuzuweisung eines Parameters verursacht werden. Ich möchte lieber einen übersichtlichen Code haben und die entfernte Chance akzeptieren, einen Parameter neu zuzuweisen, der einen Fehler verursacht. Seien Sie vorsichtig beim Schreiben / Ändern von Code.
Steve Kuo

4

Ich stimme zu, dass das finalKeyword die Lesbarkeit verbessert. Es macht es viel einfacher zu verstehen, wann ein Objekt unveränderlich ist. In Java ist es jedoch äußerst ausführlich, insbesondere (meiner Meinung nach), wenn es für Parameter verwendet wird. Das soll nicht heißen, dass die Leute es nicht benutzen sollten, weil es ausführlich ist, sondern sie benutzen es nicht, weil es ausführlich ist.

Eine andere Sprache, wie Scala, macht es viel einfacher, endgültige Erklärungen abzugeben ( val ). In diesen Sprachen können Abschlussdeklarationen häufiger vorkommen als Variablen.

Beachten Sie, dass das Schlüsselwort final auf viele verschiedene Arten verwendet werden kann. Ihr Beitrag deckt hauptsächlich die Punkte 2 und 3 ab.

  1. Abschlussklassen (JLS 8.1.1.2)
  2. endgültige Felder (JLS 8.3.1.2)
  3. endgültige Methoden (JLS 8.4.3.3)
  4. endgültige Variablen (JLS 4.12.4)

2

Zunächst einmal befürworten oder verbieten offizielle Java- Code-Konventionen keine bestimmte Verwendung von final. Das heißt, JDK-Entwickler können frei wählen, wie sie es bevorzugen.

Ich kann ihre Gedanken nicht lesen, aber für mich war finales eine Frage des Fokus, ob man sie benutzt oder nicht. Eine Frage, ob ich genug Zeit habe, um mich gründlich auf den Code zu konzentrieren oder nicht .

  • Angenommen, in einem meiner Projekte könnten wir es uns leisten, durchschnittlich 100 Codezeilen pro Tag zu verwenden. In diesem Projekt wurde ich deutlich finalals Müll wahrgenommen, der nur Dinge verdeckt, die im Code bereits deutlich genug zum Ausdruck gebracht werden. Offenbar fallen JDK-Entwickler auch in diese Kategorie.
     
    Auf der anderen Seite war es bei einem anderen Projekt völlig anders, bei dem wir durchschnittlich eine Stunde mit 100 Codezeilen verbracht haben. Dort schoss ich finalwie eine Maschinenpistole in meinem eigenen Code und im Code eines anderen - einfach, weil es der schnellste Weg war, eine Absicht des Mannes zu erkennen, der sie vor mir schrieb, und ebenso der schnellste Weg, meine eigene Absicht mitzuteilen der Typ, der später an meinem Code arbeiten wird.

Es kann auch dem JIT einen kleinen Schub verleihen, und obwohl dies ein sehr begrenzter ist, kann es nicht schaden

Argumentation wie oben ist rutschig. Vorzeitige Optimierung kann schaden; Donald Knuth geht so weit, es "die Wurzel allen Übels" zu nennen . Lass dich nicht fangen. Schreibe dummen Code .


2

Kürzlich entdeckte ich die Freude an der Funktion "Aktionen speichern" in Eclipse IDE. Ich kann ihn zwingen, meinen Code neu zu formatieren, fehlende @OverrideAnmerkungen einzufügen und einige raffinierte Dinge zu tun, z. B. unnötige Klammern in Ausdrücken zu entfernen oder das finalSchlüsselwort bei jedem Treffer automatisch überallhin zu setzen ctrl + S. Ich habe einige dieser Auslöser aktiviert und, Junge, es hilft sehr!

Es stellte sich heraus, dass viele dieser Auslöser wie eine schnelle Überprüfung der Integrität meines Codes wirken.

  • Ich wollte eine Methode überschreiben, aber die Anmerkung wurde nicht angezeigt, als ich traf ctrl + s? - Vielleicht habe ich irgendwo Parametertypen vermasselt!
  • Einige Klammern wurden beim Speichern aus dem Code entfernt? - Vielleicht ist dieser logische Ausdruck für einen Programmierer viel zu schwierig, um sich schnell zurechtzufinden. Warum sollte ich diese Klammern sonst erst hinzufügen?
  • Dieser Parameter oder diese lokale Variable ist es nicht final. Ist es hat , um seinen Wert zu ändern?

Es stellte sich heraus, dass je weniger Variablen sich ändern, desto weniger Probleme habe ich beim Debuggen. Wie oft haben Sie den Wert einer Variablen verfolgt, nur um festzustellen, dass er sich irgendwie von etwa 5 auf 7 ändert? "Wie zum Teufel könnte es sein ?!" Du fragst dich und verbringst die nächsten paar Stunden damit, unzählige Methoden ein- und auszuschalten, um herauszufinden, dass du einen Fehler in deiner Logik gemacht hast. Und um das Problem zu beheben, müssen Sie ein weiteres Flag und einige Bedingungen hinzufügen und hier und da einige Werte sorgfältig ändern.

Oh, ich hasse das Debuggen! Jedes Mal, wenn ich den Debugger starte, habe ich das Gefühl, dass meine Zeit knapp wird und ich brauche dringend diese Zeit, um zumindest einige meiner Kindheitsträume wahr werden zu lassen! Zum Teufel mit dem Debuggen! finals bedeutet keine mysteriösen Wertänderungen mehr. Mehr finals => weniger schwache Teile in meinem Code => weniger Bugs => mehr Zeit für gute Sachen!

Was finalKlassen und Methoden angeht, ist mir das eigentlich egal. Ich liebe Polymorphismus. Polymorphismus bedeutet Wiederverwendung bedeutet weniger Code bedeutet weniger Fehler. JVM leistet ohnehin gute Arbeit mit Devirtualisierung und Methoden-Inlining, daher sehe ich keinen Nutzen darin, Möglichkeiten für die Wiederverwendung von Code zu töten, um unzulängliche Leistungsvorteile zu erzielen.


Es finalist zunächst etwas ablenkend, all diese s im Code zu sehen, und es braucht Zeit, um sich daran zu gewöhnen. Einige meiner Teamkollegen sind immer noch sehr überrascht, so viele finalKeywords zu sehen. Ich wünschte, es gäbe eine Einstellung in der IDE für die spezielle Syntaxfärbung dafür. Ich würde es gerne auf einen Grauton (wie Anmerkungen) ändern, damit sie beim Lesen von Code nicht zu sehr ablenken. Eclipse hat derzeit eine separate Farbe für returnund alle anderen Schlüsselwörter, jedoch nicht für final.


1
Sie könnten sich vielleicht mit funktionalen Sprachen wie OCaml oder F # befassen. Diese Sprachen erfordern in der Regel viel weniger Debugging. Einer der Gründe dafür ist, dass standardmäßig nur Lesezugriff besteht. Einfach ausgedrückt, ändert sich eine einmal zugewiesene Variable in einer funktionalen Sprache nicht.
Abel

1
Ja, das weiß ich und von Zeit zu Zeit schreibe ich tatsächlich etwas ML-Code - da habe ich mich inspirieren lassen :) Es geht nicht um die Sprache, die Sie verwenden, sondern um die Prinzipien und Techniken, die Sie anwenden. Mit Haskell und doNotation kann man alles machen :) Sicher, Java ist nicht die beste Sprache für das Schreiben in funktionalem Stil, aber es erlaubt Ihnen zumindest, robusten Code zu schreiben - und das ist es, was mir wirklich wichtig ist.
Andrew Андрей Листочкин
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.