Остановить переназначение переменной
Хотя эти ответы интеллектуально интересны, я не прочитал короткий простой ответ:
Используйте ключевое слово final, если вы хотите, чтобы компилятор предотвращал переназначение переменной другому объекту.
Независимо от того, является ли переменная статической переменной, переменной-членом, локальной переменной или переменной аргумента / параметра, эффект полностью одинаков.
пример
Давайте посмотрим эффект в действии.
Рассмотрим этот простой метод, в котором обеим переменным ( arg и x ) могут быть назначены разные объекты.
// 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.
}
Пометьте локальную переменную как окончательную . Это приводит к ошибке компилятора.
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";
}
Вместо этого давайте пометим переменную параметра как окончательную . Это также приводит к ошибке компилятора.
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.
}
Мораль истории:
Если вы хотите, чтобы переменная всегда указывала на один и тот же объект, отметьте переменную final .
Никогда не переназначать аргументы
Как хорошая практика программирования (на любом языке), вы никогда не должны повторно назначать переменную параметра / аргумента объекту, отличному от объекта, переданного вызывающим методом. В приведенных выше примерах никогда не следует писать строкуarg =
. Поскольку люди делают ошибки, а программисты - люди, давайте попросим компилятор помочь нам. Пометьте каждую переменную параметра / аргумента как 'final', чтобы компилятор мог найти и пометить любое такое переназначение.
Ретроспективно
Как отмечалось в других ответах… Учитывая первоначальную цель разработки Java, заключающуюся в том, чтобы помочь программистам избежать глупых ошибок, таких как чтение за концом массива, Java должна была быть спроектирована так, чтобы автоматически приводить в действие все переменные параметра / аргумента как «final». Другими словами, Аргументы не должны быть переменными . Но задним числом является видение 20/20, и дизайнеры Java были заняты в то время.
Итак, всегда добавлять final
ко всем аргументам?
Должны ли мы добавить final
к каждому объявленному параметру метода?
- В теории да.
- На практике нет.
➥ Добавляйте final
только тогда, когда код метода длинный или сложный, где аргумент может быть принят за локальную переменную или переменную-член и, возможно, переназначен.
Если вы согласны с тем, что никогда не будете повторно назначать аргумент, вы будете склонны добавлять final
к каждому из них. Но это утомительно и затрудняет чтение декларации.
Для короткого простого кода, где аргумент, очевидно, является аргументом, а не локальной переменной или переменной-членом, я не беспокоюсь о добавлении final
. Если код достаточно очевиден, и у меня нет шансов, что ни я, ни какой-либо другой программист не выполнят обслуживание или рефакторинг, случайно приняв переменную аргумента за что-то отличное от аргумента, тогда не беспокойтесь. В моей собственной работе я добавляю final
только более длинный или более сложный код, где аргумент может быть принят за локальную переменную или переменную-член.
Еще один случай, добавленный для полноты
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
}