Die Neuzuweisung einer Variable stoppen
Obwohl diese Antworten intellektuell interessant sind, habe ich die kurze, einfache Antwort nicht gelesen:
Verwenden Sie das Schlüsselwort endgültig wenn Sie wollen, dass der Compiler eine verhindern soll, dass eine Variable einem anderen Objekt erneut zugewiesen wird.
Unabhängig davon, ob es sich bei der Variablen um eine statische Variable, eine Member-Variable, eine lokale Variable oder eine Argument/Parameter-Variable handelt, ist die Wirkung völlig gleich.
Beispiel
Schauen wir uns die Wirkung in Aktion an.
Betrachten wir diese einfache Methode, bei der die beiden Variablen ( arg y x ) können beide anderen Objekten zugewiesen werden.
// Example use of this method:
// this.doSomething( "tiger" );
void doSomething( String arg ) {
String x = arg; // Both variables now point to the same String object.
x = "elephant"; // This variable now points to a different String object.
arg = "giraffe"; // Ditto. Now neither variable points to the original passed String.
}
Markieren Sie die lokale Variable als endgültig . Dies führt zu einem Compilerfehler.
void doSomething( String arg ) {
final String x = arg; // Mark variable as 'final'.
x = "elephant"; // Compiler error: The final local variable x cannot be assigned.
arg = "giraffe";
}
Stattdessen markieren wir die Parametervariable als endgültig . Auch dies führt zu einem Compilerfehler.
void doSomething( final String arg ) { // Mark argument as 'final'.
String x = arg;
x = "elephant";
arg = "giraffe"; // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}
Die Moral von der Geschicht':
Wenn Sie sicherstellen wollen, dass eine Variable immer auf dasselbe Objekt zeigt, markieren Sie die Variable endgültig .
Niemals Argumente neu zuordnen
Als gute Programmierpraxis (in jeder Sprache), sollten Sie niemals eine Parameter-/Argumentvariable einem anderen Objekt als dem von der aufrufenden Methode übergebenen Objekt neu zuweisen. In den obigen Beispielen sollte man niemals die Zeile arg =
. Da Menschen Fehler machen und Programmierer auch nur Menschen sind, sollten wir den Compiler bitten, uns zu helfen. Kennzeichnen Sie jede Parameter-/Argumentvariable als "endgültig", damit der Compiler derartige Neuzuweisungen finden und kennzeichnen kann.
Im Rückblick
Wie in anderen Antworten erwähnt In Anbetracht des ursprünglichen Ziels von Java, Programmierern zu helfen, dumme Fehler zu vermeiden, wie z.B. das Lesen über das Ende eines Arrays hinaus, hätte Java so entworfen werden sollen, dass alle Parameter/Argumentvariablen automatisch als 'final' erzwungen werden. Mit anderen Worten, Argumente sollten keine Variablen sein . Aber im Nachhinein ist man immer schlauer, und die Java-Entwickler hatten damals alle Hände voll zu tun.
Fügen Sie also immer final
auf alle Argumente?
Sollten wir hinzufügen final
zu jedem einzelnen deklarierten Methodenparameter?
- Theoretisch, ja.
- In der Praxis: nein.
hinzufügen final
nur, wenn der Code der Methode lang oder kompliziert ist und das Argument fälschlicherweise für eine lokale oder Mitgliedsvariable gehalten und möglicherweise neu zugewiesen werden kann.
Wenn Sie der Praxis folgen, ein Argument niemals neu zuzuordnen, werden Sie dazu neigen, eine final
für jeden. Aber das ist mühsam und macht die Erklärung etwas unübersichtlicher.
Bei kurzem, einfachem Code, bei dem das Argument offensichtlich ein Argument und weder eine lokale Variable noch eine Mitgliedsvariable ist, mache ich mir nicht die Mühe, den Zusatz final
. Wenn der Code ziemlich offensichtlich ist und weder ich noch ein anderer Programmierer, der Wartungsarbeiten oder Refactoring durchführt, die Argumentvariable versehentlich als etwas anderes als ein Argument interpretieren kann, dann ist das nicht weiter schlimm. In meiner eigenen Arbeit, füge ich final
nur in längerem oder kompliziertem Code, wo ein Argument fälschlicherweise für eine lokale oder Mitgliedsvariable gehalten werden könnte.
Ein weiterer Fall wurde der Vollständigkeit halber hinzugefügt.
public class MyClass {
private int x;
//getters and setters
}
void doSomething( final MyClass arg ) { // Mark argument as 'final'.
arg = new MyClass(); // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
arg.setX(20); // allowed
// We can re-assign properties of argument which is marked as final
}
record
Java 16 bringt die neue Datensätze Eigenschaft. Ein Datensatz ist eine sehr kurze Art, eine Klasse zu definieren, deren Hauptzweck darin besteht, Daten unveränderbar und transparent zu übertragen.
Sie deklarieren einfach den Klassennamen zusammen mit den Namen und Typen der Mitgliedsfelder. Der Compiler liefert implizit den Konstruktor, die Getter, equals
& hashCode
und toString
.
Die Felder sind schreibgeschützt und haben keine Setzer. Also ein record
ist ein Fall, in dem es nicht notwendig ist, die Argumente zu markieren final
. Sie sind bereits effektiv endgültig. In der Tat verbietet der Compiler die Verwendung von final
bei der Deklaration der Felder eines Datensatzes.
public record Employee( String name , LocalDate whenHired ) // Marking `final` here is *not* allowed.
{
}
Wenn Sie einen optionalen Konstruktor bereitstellen, können Sie dort kann mark final
.
public record Employee(String name , LocalDate whenHired) // Marking `final` here is *not* allowed.
{
public Employee ( final String name , final LocalDate whenHired ) // Marking `final` here *is* allowed.
{
this.name = name;
whenHired = LocalDate.MIN; // Compiler error, because of `final`.
this.whenHired = whenHired;
}
}