Argumente der Java-Methode als endgültig festlegen

91

Welchen Unterschied finalmacht das zwischen dem Code unten. Gibt es einen Vorteil zu erklären , die Argumente als final.

public String changeTimezone( Timestamp stamp, Timezone fTz, Timezone toTz){  
    return ....
}

public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
        final Timezone toTz){
    return ....
}
John
quelle
4
Es gibt Codeanalysatoren, die warnen, wenn ein Parameter erneut verwendet oder neu zugewiesen wird. (Gleiches gilt für lokale Variablen.) IMHO, Dies ist eine bessere Möglichkeit, solche Parameter abzufangen, wenn Sie eine Änderung nicht wünschenswert finden.
Peter Lawrey
Ich bin der Meinung, dass Java standardmäßig alle Argumente der Eingabemethode als endgültig festlegen sollte. Und wenn ich dann die Referenz ändern möchte, müsste ich dies manuell tun. Auf diese Weise würde der Schuldfaktor viele solcher Fälle verhindern.
Sid

Antworten:

131

Da ein formaler Methodenparameter eine lokale Variable ist, können Sie von inneren anonymen Klassen nur dann auf sie zugreifen, wenn sie als endgültig deklariert sind.

Dies erspart Ihnen die Deklaration einer weiteren lokalen Endvariablen im Methodenkörper:

 void m(final int param) {
        new Thread(new Runnable() {
            public void run() {
                System.err.println(param);
            }
        }).start();
    }
PeterMmm
quelle
27
+1: Dies ist ein wichtiger Anwendungsfall und das einzige Mal, wenn Sie ihn benötigen . (Der Rest der Zeit ist nur eine Frage der Bequemlichkeit, um dem Programmierer zu helfen.)
Donal Fellows
3
Darf ich nach den Gründen fragen?
KodeWarrior
20
Mit Java 8 nicht mehr erforderlich.
Amit Parashar
3
@ Simgineer lesen Sie hier: stackoverflow.com/questions/28408109/…
PeterMmm
3
@AmitParashar Richtig, aber Java 8 erspart Ihnen nur die Verwendung des Schlüsselworts "final" jedes Mal, wenn Sie die Variable in einer inneren Klasse verwenden müssen ... Die Realität ist, dass der Compiler lediglich die Finalität implizit macht, Sie immer noch Die Variable muss effektiv endgültig sein ... Sie erhalten also immer noch einen Fehler bei der Kompilierung, falls Sie später versuchen, sie zuzuweisen! Java 8 : SNEAK 100 :)
Varun
38

Auszug aus Das letzte Wort des letzten Schlüsselworts

Endparameter

Das folgende Beispiel deklariert die endgültigen Parameter:

public void doSomething(final int i, final int j)
{
  // cannot change the value of i or j here...
  // any change would be visible only inside the method...
}

final wird hier verwendet, um sicherzustellen, dass die beiden Indizes i und j nicht versehentlich von der Methode zurückgesetzt werden. Dies ist eine praktische Möglichkeit, sich vor einem heimtückischen Fehler zu schützen, der den Wert Ihrer Parameter fälschlicherweise ändert. Im Allgemeinen sind kurze Methoden ein besserer Weg, um sich vor dieser Fehlerklasse zu schützen, aber endgültige Parameter können eine nützliche Ergänzung Ihres Codierungsstils sein.

Beachten Sie, dass endgültige Parameter nicht als Teil der Methodensignatur betrachtet werden und vom Compiler beim Auflösen von Methodenaufrufen ignoriert werden. Parameter können als endgültig (oder nicht) deklariert werden, ohne dass dies Einfluss darauf hat, wie die Methode überschrieben wird.

pgras
quelle
17
In diesem Beispiel ist es möglicherweise besser, Objekte anstelle von Grundelementen zu verwenden, da primitive Änderungen immer nur innerhalb der Methode sichtbar sind. Und bei Objekten können Sie diese trotzdem ändern. Sie können einfach nicht auf ein neues Objekt zeigen. Tatsächlich denke ich jetzt darüber nach, dass final nichts wirklich ändert, anstatt es wegzulassen, außer eine Variablendeklaration mit AICs zu speichern und den Compiler auf versehentliche Änderungen von Parametern hinweisen zu lassen, die Sie aus irgendeinem Grund nicht ändern wollten .
Rob Grant
26

Das Finale verhindert, dass Sie der Variablen einen neuen Wert zuweisen. Dies kann beim Abfangen von Tippfehlern hilfreich sein. Stilistisch möchten Sie möglicherweise die empfangenen Parameter unverändert lassen und nur lokalen Variablen zuweisen, sodass final dazu beitragen würde, diesen Stil durchzusetzen.

Ich muss zugeben, dass ich selten daran denke, final für Parameter zu verwenden, vielleicht sollte ich es tun.

public int example(final int basicRate){
    int discountRate;

    discountRate = basicRate - 10;
    // ... lots of code here 
    if ( isGoldCustomer ) {
        basicRate--;  // typo, we intended to say discountRate--, final catches this
    }
    // ... more code here

    return discountRate;
}
djna
quelle
1
Ein gutes Beispiel dafür, wie nützlich es sein kann, Argumente als endgültig zu deklarieren. Ich bin ein Teil davon, aber sie sind auch ein Schluck für 3+ Parameter.
JoseHdez_2
14

Es macht keinen großen Unterschied. Es bedeutet nur, dass Sie nicht schreiben können:

stamp = null;
fTz = new ...;

aber du kannst trotzdem schreiben:

stamp.setXXX(...);
fTz.setXXX(...);

Dies ist hauptsächlich ein Hinweis für den Wartungsprogrammierer, der Ihnen folgt, dass Sie dem Parameter irgendwo in der Mitte Ihrer Methode keinen neuen Wert zuweisen werden, wenn dies nicht offensichtlich ist und daher Verwirrung stiften kann.

Adrian Pronk
quelle
3

Das letzte Schlüsselwort bei Verwendung für Parameter / Variablen in Java markiert die Referenz als endgültig. Wenn ein Objekt an eine andere Methode übergeben wird, erstellt das System eine Kopie der Referenzvariablen und übergibt sie an die Methode. Indem Sie die neuen Referenzen als endgültig markieren, schützen Sie sie vor einer Neuzuweisung. Es wird manchmal als eine gute Codierungspraxis angesehen.

Sid
quelle
1
Ich muss etwas hinzufügen: Wenn Parameter primitiv sind, sehe ich keine Unterschiede. Wenn es sich bei den Parametern um Sammlungen handelt (eine Liste von Objekten ...), kann das Hinzufügen von final nicht verhindern, dass sie geändert werden.
Sam003
1
Unveränderlichkeit ist immer ein wünschenswertes Merkmal. Java hat es nicht sofort einsatzbereit. Das endgültige Festlegen von Variablen stellt zumindest die Referenzintegrität sicher.
Sid
1
Genau. Aber wenn wir wirklich Unveränderlichkeit für Objekte erreichen wollen, könnten wir versuchen, einen tiefen Klon zu erstellen.
Sam003
2

Für den Hauptteil dieser Methode verhindert das finalSchlüsselwort, dass die Argumentreferenzen versehentlich neu zugewiesen werden, was in diesen Fällen zu einem Kompilierungsfehler führt (die meisten IDEs beschweren sich sofort). Einige mögen argumentieren, dass die Verwendung finalim Allgemeinen, wann immer dies möglich ist, die Dinge beschleunigen wird, aber dies ist in neueren JVMs nicht der Fall.

dimitrisli
quelle
2

Zwei Vorteile, die ich sehe, sind aufgeführt:

1 Durch Markieren des Methodenarguments als endgültig wird eine Neuzuweisung des Arguments innerhalb der Methode verhindert

Von Ihrem Beispiel

    public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
            final Timezone toTz){
    
    // THIS WILL CAUSE COMPILATION ERROR as fTz is marked as final argument

      fTz = Calendar.getInstance().getTimeZone();     
      return ..
    
    }

Bei einer komplizierten Methode hilft das Markieren der Argumente als endgültig bei der versehentlichen Interpretation dieser Argumente als Methoden. Lokale Variablen und die Neuzuweisung als Compiler kennzeichnen diese Fälle wie im Beispiel gezeigt.

2 Übergabe des Arguments an eine anonyme innere Klasse

Da ein formaler Methodenparameter eine lokale Variable ist, können Sie von inneren anonymen Klassen nur dann auf sie zugreifen, wenn sie als endgültig deklariert sind.

Santhosh Urumese
quelle
1

- In der Vergangenheit (vor Java 8 :-))

Die Verwendung des Schlüsselworts "final" beeinflusste die Zugänglichkeit der Methodenvariablen für interne anonyme Klassen.

- In der modernen Sprache (Java 8+) ist eine solche Verwendung nicht erforderlich:

Java führte "effektiv endgültige" Variablen ein. Lokale Variablen und Methodenparameter werden als endgültig angenommen, wenn der Code keine Änderung des Werts der Variablen impliziert. Wenn Sie ein solches Schlüsselwort in Java8 + sehen, können Sie davon ausgehen, dass es nicht erforderlich ist. Durch die Einführung von "effektiv endgültig" geben wir weniger Code ein, wenn wir Lambdas verwenden.

Witold Kaczurba
quelle
0

Es ist nur ein Konstrukt in Java, mit dem Sie einen Vertrag definieren und sich daran halten können. Eine ähnliche Diskussion hier: http://c2.com/cgi/wiki?JavaFinalConsideredEvil

Übrigens - (wie das Twiki sagt), das Markieren von Argumenten als endgültig ist im Allgemeinen überflüssig, wenn Sie guten Programmierprinzipien folgen und die Referenz für eingehende Argumente neu zuweisen / neu definieren.

Wenn Sie die args-Referenz im schlimmsten Fall neu definieren, hat dies keine Auswirkungen auf den tatsächlichen Wert, der an die Funktion übergeben wird, da nur eine Referenz übergeben wurde.

madhurtanwani
quelle
0

Ich spreche davon, Variablen und Felder im Allgemeinen als endgültig zu markieren - gilt nicht nur für Methodenargumente. (Das Markieren von Methoden / Klassen endgültig ist eine ganz andere Sache).

Dies ist ein Gefallen für die Leser / zukünftigen Betreuer Ihres Codes. Zusammen mit einem vernünftigen Namen der Variablen ist es für den Leser Ihres Codes hilfreich und beruhigend zu sehen / verstehen, was die fraglichen Variablen darstellen - und es ist für den Leser beruhigend, dass die Bedeutung erhalten bleibt, wenn Sie die Variable im selben Bereich sehen das gleiche, so muss er sich nicht am Kopf kratzen, um immer herauszufinden, was eine Variable in jedem Kontext bedeutet. Wir haben zu viele Missbräuche bei der "Wiederverwendung" von Variablen gesehen, was selbst ein kurzes Code-Snippet schwer verständlich macht.

STRAHL
quelle
-3

Das letzte Schlüsselwort verhindert, dass Sie dem Parameter einen neuen Wert zuweisen. Ich möchte dies anhand eines einfachen Beispiels erklären

Angenommen, wir haben eine Methode

Methode 1(){

Date dateOfBirth = neues Datum ("01.01.2009");

method2 (dateOfBirth);

method3 (dateOfBirth); }}

public mehod2 (Date dateOfBirth) {
....
....
....
}

public mehod2 (Date dateOfBirth) {
....
....
....
}

In dem obigen Fall würde, wenn dem "dateOfBirth" in Methode2 ein neuer Wert zugewiesen wird, dies zu einer falschen Ausgabe von Methode3 führen. Da der Wert, der an Methode3 übergeben wird, nicht der Wert ist, der vor der Übergabe an Methode2 war. Um dieses endgültige Schlüsselwort zu vermeiden, wird es für Parameter verwendet.

Dies ist auch eine der Best Practices für die Java-Codierung.

Kamal
quelle
5
Das ist nicht ganz richtig. Selbst wenn das Argument dateOfBirth in method2 () in einen anderen Wert geändert wird, hat dies keine Auswirkung auf method2 (), da Java als Wert und nicht als Referenz übergeben wird.
Flo