Zatrzymaj zmianę przypisania zmiennej
Chociaż te odpowiedzi są interesujące intelektualnie, nie przeczytałem krótkiej prostej odpowiedzi:
Użyj słowa kluczowego final, jeśli chcesz, aby kompilator nie mógł zostać ponownie przypisany do innego obiektu.
Niezależnie od tego, czy zmienna jest zmienną statyczną, zmienną składową, zmienną lokalną lub zmienną argument / parametr, efekt jest całkowicie taki sam.
Przykład
Zobaczmy efekt w akcji.
Rozważ tę prostą metodę, w której obydwu zmiennym ( arg i x ) można przypisać różne obiekty.
// 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.
}
Oznacz zmienną lokalną jako końcową . Powoduje to błąd kompilatora.
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";
}
Zamiast tego oznaczmy zmienną parametru jako końcową . To również powoduje błąd kompilatora.
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.
}
Morał historii:
Jeśli chcesz mieć pewność, że zmienna zawsze wskazuje ten sam obiekt, zaznacz zmienną jako końcową .
Nigdy nie przypisuj ponownie argumentów
Jako dobrą praktykę programowania (w dowolnym języku), nigdy nie należy ponownie przypisywać zmiennej parametr / argument do obiektu innego niż obiekt przekazany przez metodę wywołującą. W powyższych przykładach nigdy nie należy pisać wiersza arg =
. Ponieważ ludzie popełniają błędy, a programiści są ludźmi, poprośmy kompilatora o pomoc. Oznacz każdą zmienną parametru / argumentu jako „końcową”, aby kompilator mógł znaleźć i oflagować takie ponowne przypisania.
Z perspektywy czasu
Jak zauważono w innych odpowiedziach… Biorąc pod uwagę pierwotny cel projektowy Javy polegający na pomocy programistom w unikaniu głupich błędów, takich jak czytanie poza końcem tablicy, Java powinna była zostać zaprojektowana w taki sposób, aby automatycznie wymuszała wszystkie zmienne parametrów / argumentów jako „ostateczne”. Innymi słowy, argumenty nie powinny być zmiennymi . Ale z perspektywy czasu to wizja 20/20, a projektanci Java mieli wtedy pełne ręce roboty.
Więc zawsze dodawaj final
do wszystkich argumentów?
Czy powinniśmy dodawać final
do każdego deklarowanego parametru metody?
- Teoretycznie tak.
- W praktyce nie.
➥ Dodawaj final
tylko wtedy, gdy kod metody jest długi lub skomplikowany, gdzie argument może zostać pomylony ze zmienną lokalną lub zmienną składową i ewentualnie ponownie przypisany.
Jeśli przejdziesz do praktyki, by nigdy nie przypisywać argumentu, będziesz skłonny dodać final
do każdego z nich. Jest to jednak uciążliwe i sprawia, że deklaracja jest nieco trudniejsza do odczytania.
W przypadku krótkiego prostego kodu, w którym argument jest oczywiście argumentem, a nie zmienną lokalną ani zmienną składową, nie zawracam sobie głowy dodaniem final
. Jeśli kod jest dość oczywisty, bez szansy, że ja lub inny programista przeprowadzę konserwację lub refaktoryzację przypadkowo pomylę zmienną argumentu jako coś innego niż argument, nie przejmuj się. W mojej własnej pracy dodaję final
tylko dłuższy lub bardziej zaangażowany kod, w którym argument mógłby pomylić się ze zmienną lokalną lub składową.
Dodano kolejną skrzynkę dla kompletności
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
}