Почему в Java нужно помечать локальные переменные и параметры метода как "окончательные"?

В Java вы можете определить локальные переменные и параметры метода с помощью ключевого слова final.

public static void foo(final int x) {
  final String qwerty = "bar"; 
}

Это приводит к невозможности переназначения x и qwerty в теле метода.

Эта практика подталкивает ваш код в сторону неизменности, что обычно считается плюсом. Но, это также имеет тенденцию загромождать код с "финалом", появляющимся везде. Что вы думаете о последнем ключевом слове для локальных переменных и параметров методов в Java?

12 ответов

Решение

Вы должны попытаться сделать это, когда это уместно. Помимо того, что он служит для предупреждения вас, когда вы "случайно" пытаетесь изменить значение, он предоставляет информацию компилятору, которая может привести к лучшей оптимизации файла класса. Это один из пунктов в книге Роберта Симмонса-младшего "Хардкорная Java". На самом деле, эта книга посвящена всей второй главе, посвященной использованию final для оптимизации и предотвращения логических ошибок. Инструменты статического анализа, такие как PMD и встроенная SA Eclipse, отмечают подобные случаи по этой причине.

Мое личное мнение, что это пустая трата времени. Я считаю, что визуальный беспорядок и добавленное многословие не стоят того.

Я никогда не был в ситуации, когда я переназначал (помните, это не делает объекты неизменяемыми, все это означает, что вы не можете переназначить другую ссылку на переменную) переменной по ошибке.

Но, конечно, это все личные предпочтения;-)

Завершение параметра final гарантирует, что значение, используемое в любом месте метода, ссылается на переданное значение. В противном случае вам придется мысленно проанализировать весь код над данным местоположением, чтобы узнать, какое значение имеет параметр в этой точке.

Следовательно, неиспользование final делает ваш код менее читаемым и обслуживаемым, само по себе:)

Конечные локальные переменные зависят от намерения и менее важны с моей точки зрения. Зависит от того, что происходит.

В случае локальных переменных я склонен избегать этого. Это вызывает визуальный беспорядок и, как правило, не нужно - функция должна быть достаточно короткой или фокусироваться на одном воздействии, чтобы вы могли быстро увидеть, что вы изменяете то, чего не должно быть.

В случае магических чисел я бы в любом случае поместил их как постоянное личное поле, а не в коде.

Я использую final только в тех случаях, когда это необходимо (например, передача значений анонимным классам).

Из-за (иногда) запутанной природы поведения Java " передача по ссылке" я определенно согласен с финализацией параметра var.

Завершение работы над локальными переменными кажется немного излишним ИМО.

Да, сделай это.

Это о читабельности. Проще думать о возможных состояниях программы, когда вы знаете, что переменные назначаются один раз и только один раз.

Достойной альтернативой является включение предупреждения IDE при назначении параметра или при назначении переменной (отличной от переменной цикла) более одного раза.

Хотя это создает небольшой беспорядок, это стоит поставить final, Например, Eclipse может автоматически поставить final если вы настроите это для этого.

Создание локальных переменных и параметров метода final важно, если вы хотите передать эти параметры в анонимные классы - как, например, вы создаете экземпляр анонимного потока и хотите получить доступ к этим параметрам в теле метода run().

Кроме того, я не уверен в выигрышах в производительности по сравнению с оптимизацией компилятора. Это зависит от конкретной реализации компилятора, хочет ли он вообще ее оптимизировать...

Будет полезно узнать о любых показателях производительности при использовании final...

У финала есть три веские причины:

  • переменные экземпляра, установленные конструктором, становятся неизменяемыми
  • методы, которые нельзя переопределить, становятся окончательными, используйте их по реальным причинам, а не по умолчанию
  • локальные переменные или параметры, используемые в анонимных классах внутри метода, должны быть окончательными

Как и методы, локальные переменные и параметры не нужно объявлять как окончательные. Как уже говорили другие, это приводит к тому, что код становится менее читабельным с минимальными затратами времени на оптимизацию производительности компилятора, что не является реальной причиной для большинства фрагментов кода.

Я позволил Eclipse сделать это для меня, когда они используются в анонимном классе, который увеличивается из-за моего использования API Google Collection.

Почему ты хочешь? Вы написали метод, поэтому любой, кто его модифицирует, всегда может удалить ключевое слово final из qwerty и переназначить его. Что касается сигнатуры метода, то же самое рассуждение, хотя я не уверен, что он будет делать с подклассами вашего класса... они могут наследовать конечный параметр и даже если они переопределят метод, не смогут де-финализировать x. Попробуйте и выясните, будет ли это работать.

Таким образом, единственное реальное преимущество заключается в том, что если вы сделаете параметр неизменным и он будет перенесен на детей. В противном случае вы просто загромождаете свой код без особых на то причин. Если это не заставит кого-либо следовать вашим правилам, вам лучше просто оставить хороший комментарий, так как вы не должны изменять этот параметр или переменную вместо того, чтобы указывать модификатор final.

редактировать

В ответ на комментарий я добавлю, что если вы сталкиваетесь с проблемами производительности, финальные локальные переменные и параметры могут позволить компилятору лучше оптимизировать ваш код. Однако, с точки зрения неизменности вашего кода, я придерживаюсь своего первоначального утверждения.

Мы делаем это здесь для локальных переменных, если думаем, что они не будут переназначены или не должны быть переназначены.

Параметры не являются окончательными, так как у нас есть Checkstyle-Check, который проверяет переназначение параметров. Конечно, никто никогда не захочет переназначить переменную параметра.

Другие вопросы по тегам