Зачем отмечать локальные переменные и параметры метода как окончательные в Java?

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

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

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

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


person Julien Chastang    schedule 25.11.2008    source источник


Ответы (12)


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

person rjray    schedule 25.11.2008
comment
+1: Всего одно дополнение - final также передает намерение автора как в параметрах, так и в локальных переменных. - person Ken Gentle; 25.11.2008
comment
Я сейчас читаю Hardcore Java. Я думал, что знаю Java ........... - person WolfmanDragon; 10.12.2008
comment
Вы уверены, что окончательные параметры locals / method могут улучшить оптимизацию компилятора? В качестве контрольной точки представьте, что вы объявляете локальную переменную int x = 2. Если вы безоговорочно никогда не переназначаете x, компилятор будет знать об этом, потому что, просканировав весь код и увидев, что x не может быть переназначен независимо от того, какое условие, он вычитает это x никогда не будет изменен ... - person L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o&#x; 28.06.2010
comment
Иронично, что PMD не использует окончательные параметры метода в своем собственном исходном коде, чтобы привести один пример. Как и большинство JDK, на которые я смотрел. Не делают и рефакторинги Eclipse, скажем, для инкапсуляции. - person Dan Rosenstark; 04.10.2010
comment
@Yar многие рефакторинги Eclipse и шаблоны генерации / завершения исходных текстов не являются примерными ... - person Gabriel Ščerbák; 18.11.2010
comment
@Gabriel Ščerbák, моя точка зрения заключалась в том, что я не единственный человек, который думает, что final на входных параметрах загромождает код из-за небольшого улучшения ясности или его отсутствия. - person Dan Rosenstark; 18.11.2010
comment
@ Яр, я не совсем уверен, что это хорошо. Он игнорирует возможности языка, потому что он плохо спроектирован. Мне не нравится, как это работает, но я более уверен в проверке доступа компилятора, чем в том, что разработчики никогда не попытаются это сделать. Тот факт, что это сделано не очень хорошо, - это проблема, которую должен решать Oracle, а не программисты. Что касается беспорядка, я предпочитаю находить окончательные параметры, а не сканировать код, если параметр не изменен. - person Gabriel Ščerbák; 18.11.2010
comment
@Gabriel Ščerbák, переменные конечного экземпляра (или статика, конечно) идеальны. Я просто сомневаюсь в необходимости пометить параметры как окончательные, потому что на самом деле это не меняет поведения ЗВОНИТЕЛЯ, так почему это часть подписи? И кого волнует, хочет ли разработчик метода повторно использовать переменную, но зачем им это делать? Есть много букв, из которых можно создавать новые переменные, не так ли? Но самое главное: ПОЧЕМУ ВЫ СДЕЛАЛИ ЭТО ОГРАНИЧЕНИЕ ПРИОРИ? Если переменная point преобразуется, а вы по-прежнему называете ее point, это ваш бизнес как разработчик метода. На звонящего не влияет. - person Dan Rosenstark; 18.11.2010
comment
@Yar AFAIK вы ошибаетесь в том, что это часть подписи, на самом деле вам не нужно указывать параметры в интерфейсе, так как final, final в реализации достаточно. Я согласен с тем, что повторное использование переменных может (и должно) быть опущено, ключевое слово final просто позволяет указать его явно. Мое мнение, как было написано ранее, должно быть неявной частью языка без поддержки синтаксиса. До тех пор я буду использовать его с помощью моей IDE. - person Gabriel Ščerbák; 19.11.2010
comment
Окончательное определение параметров метода не может повлиять на производительность, поскольку оно не является частью скомпилированного файла класса. Лично я этого не делаю (это значительно загромождает код, и важно, чтобы сигнатуры методов были удобочитаемыми ... и проще иметь хорошие привычки!), Хотя если вы отлаживаете плохо написанные и слишком длинные может иметь смысл добавить final ко всему, чтобы быстро увидеть, есть ли там проблемы с переназначением. - person Rob Whelan; 23.04.2011

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

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

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

person SCdF    schedule 25.11.2008
comment
+1, потому что я думаю, что речь идет не только о теле метода и логических ошибках (с которыми я никогда не сталкивался только из-за не конечных переменных, FWIW), но и о читаемых сигнатурах методов. Я не вижу, как параметр, объявленный как final, делает подпись более читаемой. Простые типы передаются по значениям, поэтому их нельзя изменить. Сложные типы передаются по ссылке, но ссылка передается по значению, поэтому не может быть изменена. Финал - просто шум для читателя подписи. - person Matthias; 18.07.2010

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

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

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

person Thorbjørn Ravn Andersen    schedule 30.08.2009
comment
Помните, что final помечает только ссылку как неизменяемую. Свойства указанного объекта могут измениться в любое время. Таким образом, вы получите такой уровень уверенности только в том случае, если сделаете весь граф объекта неизменяемым. Тем не менее, это очень хорошая практика, даже несмотря на то, что этого трудно добиться в java. - person ordnungswidrig; 21.11.2011
comment
Это гарантирует, что упомянутый объект такой же. содержимое указанного объекта, естественно, может измениться. - person Thorbjørn Ravn Andersen; 21.11.2011

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

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

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

person Uri    schedule 25.11.2008

Я определенно согласен с доработкой параметра var.

Доработка локальных var кажется несколько излишней IMO.

person javamonkey79    schedule 25.11.2008
comment
Но если вы передадите список по ссылке и пометите его как окончательный в списке параметров, вы все равно сможете добавлять или удалять элементы и видеть их отражение в вызывающей стороне - это, безусловно, БОЛЬШЕ сбивает с толку, чем в этом случае не указывать final для параметра? - person mjaggard; 30.01.2012
comment
Не обязательно. Изменяемость объектов - это довольно новая концепция IMO. Там, где я работаю, мы ожидаем, что разработчики поймут, что окончательный объект не означает, что он не может измениться, просто на него нельзя ссылаться повторно. - person javamonkey79; 30.01.2012

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

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

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

person Craig P. Motlin    schedule 03.12.2008
comment
finalized не сохраняет параметр или переменную от изменения, это не похоже на const в C ++. Передайте список в последний параметр, и вы все равно можете его очистить. - person Arne Burmeister; 03.01.2009
comment
Дело не в безопасности, а в удобочитаемости. Очевидно, что создание параметра final не влияет на то, какие состояния возможны в конце метода. - person Craig P. Motlin; 05.01.2009
comment
@Motlin: он подходит для примитивов и неизменяемых объектов, что, по моему опыту, охватывает множество параметров. - person Andrew Swan; 13.02.2009
comment
@ Андрей Я говорю о состоянии в куче, а не о стеке, который все равно вот-вот потеряется. Нет никаких побочных эффектов, которые возможны с неокончательными параметрами, которые вы не можете сделать с конечными параметрами. - person Craig P. Motlin; 13.02.2009

final имеет три веские причины:

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

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

person Arne Burmeister    schedule 25.11.2008

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

person fastcodejava    schedule 03.10.2010

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

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

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

person kartheek    schedule 04.10.2010

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

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

Изменить

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

person Elie    schedule 25.11.2008
comment
JRE или компилятор могут выполнить дополнительную оптимизацию, если знают, что объект завершен. - person paxdiablo; 25.11.2008
comment
Конечно, но вопрос был не в этом. С точки зрения того, чтобы сделать ваш код неизменным, на самом деле это не работает. Однако вы совершенно правы в том, что это может быть немного быстрее, чем его не использовать, и это следует учитывать, когда производительность является проблемой. - person Elie; 25.11.2008
comment
Когда я прокомментировал ответ Pax, я почти уверен, что нет улучшений производительности, сделав локальные переменные final, поскольку JVM может угадать это за вас. - person SCdF; 25.11.2008
comment
Нет, просто улучшения компилятора, но кого это волнует. Теперь мне лень снова поправляться. Ну что ж.... - person Elie; 25.11.2008
comment
Завершение параметра не является оптимизацией. Последний флаг удаляется во время компиляции. Он используется только компилятором, а не во время выполнения. - person Robin; 25.11.2008

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

person Miserable Variable    schedule 25.11.2008

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

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

person boutta    schedule 25.11.2008