it-swarm-eu.dev

Warum endgültige Variablen in Methoden deklarieren?

Als ich einige Klassen von Android studierte, stellte ich fest, dass die meisten Variablen von Methoden als endgültig deklariert sind.

Beispielcode aus der Klasse Android.widget.ListView:

/**
* @return Whether the list needs to show the top fading Edge
*/
private boolean showingTopFadingEdge() {
    final int listTop = mScrollY + mListPadding.top;
    return (mFirstPosition > 0) || (getChildAt(0).getTop() > listTop);
}

/**
 * @return Whether the list needs to show the bottom fading Edge
 */
private boolean showingBottomFadingEdge() {
    final int childCount = getChildCount();
    final int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();
    final int lastVisiblePosition = mFirstPosition + childCount - 1;
    final int listBottom = mScrollY + getHeight() - mListPadding.bottom;
    return (lastVisiblePosition < mItemCount - 1)
                     || (bottomOfBottomChild < listBottom);
}

Was ist die Absicht, in diesen Fällen das endgültige Schlüsselwort zu verwenden?

76
Rodrigo

Ich würde sagen, dass dies auf Kraft der Gewohnheit zurückzuführen ist. Der Programmierer, der diesen Code geschrieben hat, wusste beim Schreiben, dass die Werte für die endgültigen Variablen nach der Zuweisung niemals geändert werden sollten, und machte sie daher endgültig. Jeder Versuch, einer endgültigen Variablen nach der Zuweisung einen neuen Wert zuzuweisen, führt zu einem Compilerfehler.

Wenn es um Gewohnheiten geht, ist es nicht schlecht, sich zu entwickeln. Wenn Sie eine Variable final erstellen, wird zumindest das Intent des Programmierers zum Zeitpunkt des Schreibens angegeben. Dies ist wichtig, da nachfolgende Programmierer, die den Code bearbeiten, möglicherweise nachdenken müssen, bevor sie die Verwendung dieser Variablen ändern.

64
Jon

Wenn ich als Java Entwickler, der standardmäßig alle Variablen final erstellt (und die Tatsache schätzt, dass Eclipse dies automatisch kann), fällt es mir leichter, über mein Programm nachzudenken, wenn Variablen werden einmal initialisiert und nie wieder geändert.

Zum einen sind nicht initialisierte Variablen kein Problem mehr, da der Versuch, eine final -Variable vor ihrer Initialisierung zu verwenden, zu einem Kompilierungsfehler führt. Dies ist besonders nützlich für verschachtelte bedingte Logik, bei der ich sicherstellen möchte, dass alle Fälle abgedeckt sind:

final int result;
if (/* something */) {
  if (/* something else */) {
    result = 1;
  }
  else if (/* some other thing */) {
    result = 2;
  }
}
else {
  result = 3;
}
System.out.println(result);

Habe ich alle Fälle abgedeckt? (Hinweis: Nein.) Sicher genug, dieser Code wird nicht einmal kompiliert.

Eine weitere Sache: Im Allgemeinen sollten Sie jedes Mal, wenn Sie wissen, dass eine Variable immer wahr ist, versuchen, Ihre Sprache dazu zu bringen, sie durchzusetzen. Wir tun dies natürlich jeden Tag, wenn wir den Typ einer Variablen angeben: Die Sprache stellt sicher, dass Werte, die nicht von diesem Typ sind, nicht in dieser Variablen gespeichert werden können. Wenn Sie wissen, dass eine Variable nicht neu zugewiesen werden sollte, weil sie bereits den Wert hat, den sie für die gesamte Methode behalten sollte, können Sie die Sprache dazu bringen, diese Einschränkung durchzusetzen, indem Sie sie final deklarieren.

Schließlich gibt es die Frage der Gewohnheit. Andere haben erwähnt, dass dies eine Gewohnheit ist (+1 bis Jon dafür ), aber lassen Sie mich etwas darüber sagen, warum Sie diese Gewohnheit wollen würden. Wenn Sie Felder in Ihrer Klasse und keine lokalen Variablen in einer Methode deklarieren, können mehrere Threads gleichzeitig auf diese Felder zugreifen. Es gibt einige obskure Ausnahmen, aber im Allgemeinen wird, wenn ein Feld endgültig ist, jeder Thread, der Ihre Klasse verwendet, denselben Wert für die Variable sehen. Wenn umgekehrt ein Feld nicht endgültig ist und mehrere Threads Ihre Klasse verwenden, müssen Sie sich um die explizite Synchronisierung mit synchronized Blöcken und/oder Klassen aus Java.util.concurrent Sorgen. Eine Synchronisation ist möglich, aber die Programmierung ist bereits schwierig genug. ;-) Wenn Sie also aus Gewohnheit nur allesfinal deklarieren, sind viele Ihrer Felder endgültig und Sie verbringen so wenig Zeit wie möglich damit, sich um die Synchronisation zu kümmern und Parallelitätsfehler.

Weitere Informationen zu dieser Angewohnheit finden Sie im Tipp "Mutabilität minimieren" in Joshua Blochs Effective Java .

Bearbeiten: @Peter Taylor hat darauf hingewiesen, dass das obige Beispiel auch nicht kompiliert werden würde, wenn das Schlüsselwort final entfernt wird, was völlig korrekt ist . Als ich geraten habe, alle lokalen Variablen endgültig zu halten, wollte ich Beispiele wie das folgende unmöglich machen:

int result = 0;

// OK, time to cover all the cases!
if (/* something */) {
  if (/* something else */) {
    result = 1;
  }
  else if (/* some other thing */) {
    result = 2;
  }
  // Whoops, missed an "else" here. Too bad.
}
else {
  result = 3;
}
System.out.println(result);  // Works fine!

Wenn ich eine neue Variable verwende, anstatt eine alte wiederzuverwenden, kann ich dem Compiler mitteilen, dass der Versuch, das gesamte Universum der Möglichkeiten abzudecken, und die Verwendung von final-Variablen mich zwingt, eine neue Variable zu verwenden, anstatt eine alte zu recyceln.

Eine weitere berechtigte Beschwerde zu diesem Beispiel ist, dass Sie zunächst komplexe verschachtelte bedingte Logik vermeiden sollten. Das stimmt natürlich, gerade weil es schwierig ist, sicherzustellen, dass Sie alle Fälle so abgedeckt haben, wie Sie es beabsichtigt haben. Manchmal kann eine komplexe Logik jedoch nicht vermieden werden. Wenn meine Logik komplex ist, möchte ich, dass meine Variablen so einfach wie möglich zu begründen sind. Dies kann erreicht werden, indem sichergestellt wird, dass sich die Werte meiner Variablen nach ihrer Initialisierung nie ändern.

53
Joe Carnahan

Wir können die Antwort nicht sicher wissen (es sei denn, wir fragen die ursprünglichen Entwickler), aber meine Vermutungen sind:

  1. Die Programmierer dieser Methoden haben möglicherweise das Gefühl, dass das Hinzufügen von "final" den Zweck dieser Variablen besser ausdrückt.
  2. Die Programmierer verwenden möglicherweise ein Tool, das automatisch "final" hinzufügt, wo dies möglich ist.
  3. Es könnte ein Optimierungstrick sein: Ich habe nicht das Wissen/die Werkzeuge, um dies selbst zu überprüfen, wäre aber interessiert, es so oder so zu wissen.
7
Kramii

Ein weiterer Grund ist, sie in inneren anonymen Klassen verwenden zu können:

public interface MyInterface {
    void foo();
} 

void myMethod() {
    final String asdf = "tada";//if not final cannot be used in inner classes
    new MyInterface() {
        @Override
        public void foo() {
             String myNewString = asdf;//does not compile only if asdf is final
        }
    }
}
6
m3th0dman

Um dumme Fehler weniger häufig zu machen. final stellt sicher, dass die Variable immer auf das zuerst zugewiesene Objekt zeigt und alle versuchten Änderungen als Fehler bei der Kompilierung gelten.

Sie können auch fragen, warum der Typ einer Variablen explizit deklariert wird oder warum Methoden in C++ als konstant deklariert werden. Gleicher Grund.

4
Yam Marcovic

Hier der Grund dafür: Vermeidung einer Neuzuweisung zu lokalen Variablen/Parametern. Dies würde die Lesbarkeit verbessern und einige dumme Fehler vermeiden.

http://sourcemaking.com/refactoring/remove-assignments-to-parameters

Auszug:

Mit Java 1.1 und späteren Versionen können Sie einen Parameter als endgültig markieren. Dies verhindert die Zuordnung zur Variablen. Sie können das Objekt, auf das sich die Variable bezieht, weiterhin ändern. Ich behandle meine Parameter immer als endgültig, aber ich gebe zu, dass ich sie in der Parameterliste selten so markiere.

2
Mik378

Ehrlich gesagt glaube ich nicht, dass es einen wirklichen Grund gibt, in diesem Zusammenhang eine Variable endgültig zu machen. Ich nehme an, sie kopieren und fügen entweder den Code ein oder möchten wirklich jeden davon abhalten, dieser Methode mehr Code hinzuzufügen, diese Variablen neu zuzuweisen.

0
programmx10