it-swarm.dev

Übermäßiges Verwenden des Schlüsselworts "final" in Java

Ich verstehe zwar, wofür das Schlüsselwort final im Kontext von Klassen und Methoden verwendet wird, sowie die Absicht seiner Verwendung in Bezug auf Variablen; Das Projekt, an dem ich gerade angefangen habe, scheint jedoch eine übermäßige Anzahl von ihnen zu haben, und ich bin gespannt auf die Logik dahinter.

Der folgende Codeausschnitt ist nur ein kurzes Beispiel, da ich im Schlüsselwort final für die Variablen key und value nicht viel Sinn sehe:

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;
}

Ich habe die Verwendung anhand von Artikeln gelesen, die ich über Google gefunden habe. Hilft das Muster jedoch wirklich dem Compiler, den Code zu optimieren?

118
rjzii

Es gibt viele Referenzen, die auf ein liberalVerwendung vonfinal hinweisen. Die Java Sprachspezifikation hat sogar ein Abschnitt über endgültige Variablen . Verschiedene Regeln in statischen Analysetools unterstützen dies ebenfalls - PMD hat sogar ein Anzahl der Regeln, die erkannt werden müssen, wann final verwendet werden kann . Die Seiten, die ich verlinkt habe, geben eine Reihe von Punkten darüber, was final tut und warum Sie sollten es großzügig verwenden.

Für mich hat die liberale Verwendung von final in den meisten Codes zwei Dinge bewirkt, und dies sind wahrscheinlich die Dinge, die den Autor Ihres Codebeispiels dazu veranlasst haben, es zu verwenden:

  1. Dies macht die Absicht des Codes viel klarer und führt zu selbstdokumentierendem Code. Die Verwendung von final verhindert, dass sich der Wert eines primitiven Objekts ändert oder ein neues Objekt erstellt wird und ein vorhandenes Objekt überschrieben wird. Wenn der Wert einer Variablen nicht geändert werden muss und jemand dies tut, gibt der IDE und/oder Compiler eine Warnung aus. Der Entwickler muss entweder das Problem beheben oder das final Modifikator aus der Variablen. In beiden Fällen sind Überlegungen erforderlich, um sicherzustellen, dass das beabsichtigte Ergebnis erzielt wird.

  2. Abhängig von Ihrem Code dient dies als Hinweis für den Compiler, um möglicherweise Optimierungen zu ermöglichen. Dies hat nichts mit der Kompilierungszeit zu tun, sondern damit, was der Compiler während der Kompilierung tun kann. Es ist auch nicht garantiert, etwas zu tun. Wenn Sie dem Compiler jedoch signalisieren, dass sich der Wert dieser Variablen oder des Objekts, auf das diese Variable verweist, niemals ändern wird, können möglicherweise Leistungsoptimierungen vorgenommen werden.

Es gibt auch andere Vorteile im Zusammenhang mit der Parallelität. Bei Anwendung auf Klassen- oder Methodenebene muss damit sichergestellt werden, was überschrieben oder vererbt werden kann. Diese gehen jedoch über den Rahmen Ihres Codebeispiels hinaus. Wiederum gehen die Artikel, die ich verlinkt habe, viel detaillierter darauf ein, wie Sie final anwenden können.

Der einzige Weg, um sicher zu sein, warum sich der Autor des Codes für die Verwendung von final entschieden hat, besteht darin, den Autor zu finden und nach sich selbst zu fragen.

127
Thomas Owens

Ich habe zwei Hauptvorteile von "final":

  • Endgültige Variablen sind "sicherer" als nicht endgültige Variablen, denn sobald sie gebunden sind, gibt es keine Frage mehr zu ihrem aktuellen Zustand.
  • Aus den oben genannten Gründen entlastet das Erstellen eines Variablen-Finales den Programmierer von übermäßigem geistigem Jonglieren - er muss den Code nicht durchsuchen, um festzustellen, ob sich die Variable geändert hat. Dieser glückliche Zustand ist jedem bekannt, der sich in einer funktionalen Sprache aufgehalten hat.

In diesem speziellen Beispiel kann es sein, dass der Programmierer die Gewohnheit "final" übernommen hat und das Schlüsselwort "final" selbstverständlich überall anwendet. (Ich bin skeptisch gegenüber der Vorstellung, dass das endgültige Schlüsselwort dem Compiler helfen würde, wenn es um einzelne Zuweisungen geht - sicherlich braucht es nicht die Hilfe, um festzustellen, dass nur eine Zuweisung stattgefunden hat?)

Ich bin der Meinung, dass Java es rückwärts bekommen hat - es sollte kein "final" -Schlüsselwort für Variablen geben, alles sollte standardmäßig "final" sein, und wenn Sie eine veränderbare Variable wollen, sollten Sie es tun Dazu muss ein Schlüsselwort hinzugefügt werden ("var" oder ein ähnliches). (Wie ein anderer Kommentator erwähnte, hat scala hat zwei Schlüsselwörter - "val" und "var" für endgültige und nicht endgültige Variablen jeweils - ich nehme es).

37
nerdytenor

In Java ist meines Wissens der einzige Ort, an dem das Schlüsselwort final erforderlich ist, um eine Variable einer anonymen Klasse zuverlässig zur Verfügung zu stellen ( da der Compiler unter den Deckblättern einige Tricks macht, die erfordern, dass sich dieser Wert nicht ändern kann).

Meines Wissens ist es ein Mythos, dass das letzte Schlüsselwort es dem Java Compiler) ermöglicht, Code zu optimieren, da alle Optimierungen, die wichtig sind , im JIT-Teil stattfinden der Laufzeit.

Es ist also Geschmackssache. Es gibt jedoch einen sehr bedeutenden Vorteil für die Verwendung vieler Finals, nämlich die Erleichterung des Lesens des Codes für zukünftige Betreuer.

Das Markieren einer Variablen als final teilt dem Leser mit, dass sich diese Variable bei ihrer Zuweisung niemals ändert. Dies ist sehr wichtig, wenn Sie Code lesen, da Sie wissen, wann Sie den Wert der Variablen kennen müssen, der mit dem Wert der ursprünglichen Zuweisung identisch ist, und nicht den gesamten Code dazwischen mental analysieren müssen, um festzustellen, ob die Variable erneut zugewiesen wird mit etwas anderem.

Auch wenn Sie sehen, dass eine Variable nicht mit final markiert ist, wissen Sie, dass sie weiter geändert wird ! Dies ist eine äußerst wichtige Information, die dem Leser übermittelt werden kann, indem einfach fünf Zeichen fehlen.

Alles, was dem Betreuer helfen kann, seine Arbeit schneller und zuverlässiger zu erledigen, bedeutet, dass die Wartung der Anwendung billiger ist! Mit anderen Worten, final spart echtes Geld.

Hinweis: Eclipse verfügt über die Option "Quellensäuberung", mit der nach Möglichkeit Endspiele eingefügt werden können. Dies kann sowohl zum Schreiben von neuem Code als auch zum Beibehalten von altem Code hilfreich sein (Finale einfügen, wenn einige fehlen, wird die Variable nach der ersten Zuweisung geändert). Mein Bauchgefühl ist, dass dies das ist, was der ursprüngliche Autor entdeckt und beschlossen hat, es zu verwenden.

Das Thema wird unter https://stackoverflow.com/q/316352/53897 weiter erläutert

13
user1249

Ich denke, die Antwort darauf ist einfacher als andere vermuten. Es geht nicht um Absicht oder Design. Vor einiger Zeit stimmte es, dass die JVM durch Hinzufügen von Final an einigen Stellen (insbesondere für Methoden und Klassen) aggressiver optimieren konnte. Infolgedessen wurden einige Leute wütend und setzten buchstäblich das Finale überall, um zu versuchen, ihren Code schneller zu machen.

Ich sollte hinzufügen, dass nicht der Compiler, sondern die JVM die Optimierung vornimmt. Darüber hinaus bezweifle ich, dass das endgültige Setzen einer lokalen Variablen jemals einen Unterschied für die Leistung gemacht hätte.

Schließlich würde die Verwendung von final heutzutage wahrscheinlich keinen großen Unterschied machen, da die JVM-Optimierungen etwas fortgeschritten sind.

8
redjamjar

Mir scheint, dass das Schlüsselwort final in diesem Zusammenhang verwendet wird, um eine unveränderliche Sammlung zu erstellen. Unveränderliche Sammlungen sind einfacher zu begründen und sicherer in Programmen zu verwenden, die Parallelität erfordern (mehrere Threads).

Das stimmt natürlich nicht. Das Schlüsselwort final garantiert nur, dass der Verweis auf die Sammlung nicht durch einen Verweis auf eine andere Sammlung oder null ersetzt werden kann.

1
Robert Harvey