Когда следует использовать final для параметров метода и локальных переменных?

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

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

Это что-то, что я должен сделать, чтобы помнить?

Одержимость:

  • Заключительные поля. Пометка полей как окончательных заставит их быть установленными до конца строительства, делая эту ссылку на поле неизменной. Это позволяет безопасно публиковать поля и может избежать необходимости синхронизации при последующих чтениях. (Обратите внимание, что для ссылки на объект только ссылка на поле неизменна – все, к чему ссылается ссылка объекта, все еще может меняться и влияет на неизменность.)
  • Конечные статические поля. Хотя теперь я использую enums для многих случаев, когда я использовал статические конечные поля.

Рассмотрите, но используйте разумно:

  • Заключительные classы – дизайн Framework / API – единственный случай, когда я его рассматриваю.
  • Окончательные методы – в основном такие же, как и конечные classы. Если вы используете шаблонные методы шаблонов, такие как сумасшедшие и маркирующие вещи, вы, вероятно, слишком полагаетесь на наследование и недостаточно на делегирование.

Игнорировать, если не почувствовать анальный:

  • Параметры метода и локальные переменные – Я РЕАЛЬНО сделаю это во многом потому, что я ленив, и я нахожу, что он загромождает код. Я полностью соглашусь с тем, что параметры маркировки и локальные переменные, которые я не собираюсь изменять, являются «более быстрыми». Мне жаль, что это не было по умолчанию. Но это не так, и я считаю, что код сложнее понять в финале. Если я нахожусь в чужом коде, я не собираюсь их вытаскивать, но если я пишу новый код, я не буду вставлять их. Одно из исключений – это случай, когда вы должны отметить что-то окончательное, чтобы вы могли получить доступ это изнутри анонимного внутреннего classа.

Это что-то, что я должен сделать, чтобы помнить?

Нет, если вы используете Eclipse, потому что вы можете настроить действие «Сохранить действие», чтобы автоматически добавлять эти окончательные модификаторы для вас. Тогда вы получаете преимущества за меньшие усилия.

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

Маркировка classа «final» означает, что вы не приложили усилий во время разработки или реализации classа, чтобы грамотно обрабатывать расширение. Если читатели могут внести изменения в class и хотят удалить «окончательный» модификатор, они могут сделать это на свой страх и риск. Это зависит от них, чтобы убедиться, что class будет хорошо работать с расширением.

Маркировка переменной «final» (и назначение ее в конструкторе) полезна при инъекции зависимостей. Это указывает на «соавторную» природу переменной.

Маркировка метода «final» полезна в абстрактных classах. Он четко определяет, где находятся точки расширения.

Я нашел параметры меток маркировки и locals, поскольку final полезен как вспомогательное средство рефакторинга, когда рассматриваемый метод является непонятным беспорядком на несколько страниц. Поймайте final либерально, посмотрите, что «не может назначить конечной переменной» ошибки, которые генерирует компилятор (или ваша IDE), и вы просто можете обнаружить, почему переменная, называемая «data», заканчивается нулевой, хотя некоторые (устаревшие) комментарии клянутся, что не может случиться.

Затем вы можете исправить некоторые ошибки, заменив повторно используемые переменные новыми переменными, объявленными ближе к точке использования. Затем вы обнаружите, что вы можете обернуть целые части метода в скобках фигур, и внезапно вы сделаете одно нажатие IDE из «Метод извлечения», и ваш монстр просто станет более понятным.

Если ваш метод еще не является недостижимым крушением, я думаю, что может быть полезно сделать окончательный материал, чтобы препятствовать тому, чтобы люди превратили его в сказанное крушение; но если это короткий метод (см .: не недостижимый), то вы рискуете добавить много многословия. В частности, сигнатуры функций Java достаточно сложны, чтобы вписаться в 80 символов, так как это не добавляет еще шесть аргументов!

Ну, это все зависит от вашего стиля … если вам нравится просмотр финала, когда вы не будете изменять эту переменную, тогда используйте ее. Если вы НЕ НРАВИТСЯ, увидев это … затем оставьте это.

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

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

Итак, я бы сказал, просто выберите направление, на которое вы наклоняетесь, и просто пойдите с ним (независимо от того, попытайтесь быть последовательным).


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

Я использую final все время, чтобы сделать Java более выраженным. См. Условия Java ( if,else,switch ) не являются выражением, которое я всегда ненавидел, особенно если вы использовали функциональное программирование (то есть ML, Scala или Lisp).

Таким образом, вы должны стараться всегда (IMHO) использовать конечные переменные при использовании условий.

Позволь мне привести пример:

  final String name; switch(pluginType) { case CANDIDATE_EXPORT: name = "Candidate Stuff"; break; case JOB_POSTING_IMPORT: name = "Blah"; break; default: throw new IllegalStateException(); } 

Теперь, если добавить другой оператор case и не задавать name компилятор завершится с ошибкой. Компилятор также потерпит неудачу, если вы не сломаете каждый случай (который вы установите для переменной). Это позволяет сделать Java очень похожим на выражения Letp’s let и делает так, чтобы ваш код не был отложен (из-за лексических переменных).

И поскольку @Recurse заметила (но, видимо, -1 меня), вы можете сделать предыдущее, не создав final String name чтобы получить ошибку компилятора (о которой я никогда не говорил, что не могу), но вы можете легко заставить ошибку компилятора уйти с имени настройки после оператора switch, который отбрасывает семантику выражения или хуже забывает break что вы не можете вызвать ошибку (несмотря на то, что говорит @Recurse) без использования final :

  String name; switch(pluginType) { case CANDIDATE_EXPORT: name = "Candidate Stuff"; //break; whoops forgot break.. //this will cause a compile error for final ;P @Recurse case JOB_POSTING_IMPORT: name = "Blah"; break; } // code, code, code // Below is not possible with final name = "Whoops bug"; 

Из-за названия настройки ошибки (кроме забывания break и другую ошибку) я могу случайно сделать это:

  String name; switch(pluginType) { case CANDIDATE_EXPORT: name = "Candidate Stuff"; break; //should have handled all the cases for pluginType } // code, code, code // Below is not possible with final name = "Whoops bug"; 

Конечная переменная заставляет выполнить единую оценку того, какое имя должно быть. Подобно тому, как функция, которая имеет возвращаемое значение, всегда должна возвращать значение (игнорируя исключения), блок переключения имен должен будет разрешить имя и, следовательно, привязан к этому блоку коммутатора, который упрощает рефакторинг fragmentов кода (например, метод репликации Eclipe: extract) ,

Вышеизложенное в OCaml:

 type plugin = CandidateExport | JobPostingImport let p = CandidateExport let name = match p with | CandidateExport -> "Candidate Stuff" | JobPostingImport -> "Blah" ;; 

match ... with ... оценивается как функция, т.е. выражение. Обратите внимание, как выглядит наш оператор switch.

Вот пример в Схеме (Racket или Chicken):

 (define name (match b ['CandidateExport "Candidate Stuff"] ['JobPostingImport "Blah"])) 

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

Если вы пишете какой-то разовый код, то, ну, не беспокойтесь, чтобы определить всю константу и сделать ее окончательной.

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

  public int processSomethingCritical( final int x, final int y ){ // hundreds of lines here // for loop here... int x2 = 0; x++; // bug aarrgg... // hundreds of lines there // if( x == 0 ) { ... } 

Конечно, в идеальном мире этого бы не случилось, но … ну .. иногда вам приходится поддерживать код других. 🙁

Я буду использовать финал, насколько смогу. Это будет означать, если вы непреднамеренно измените поле. Я также задал параметры метода final. Сделав это, я обнаружил несколько ошибок из кода, который я взял, когда они пытаются «установить» параметр, забывающий пропуски Java по значению.

Из вопроса неясно, очевидно ли это, но включение параметра параметра метода влияет только на тело метода. Он НЕ передает никакой интересной информации о намерениях метода для invoker. Передаваемый объект все еще может быть мутирован внутри метода (финалы не являются константами), а область действия переменной находится внутри метода.

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

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

Существует много применений для переменной final . Здесь только несколько

Конечные константы

  public static class CircleToolsBetter { public final static double PI = 3.141; public double getCircleArea(final double radius) { return (Math.pow(radius, 2) * PI); } } 

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

Конечные переменные

 public static String someMethod(final String environmentKey) { final String key = "env." + environmentKey; System.out.println("Key is: " + key); return (System.getProperty(key)); } } 

В этом classе вы создаете конечную переменную с округлением, которая добавляет префикс к параметру environmentKey. В этом случае конечная переменная является окончательной только в пределах области выполнения, которая отличается при каждом выполнении метода. Каждый раз, когда вводится метод, окончательный реконструируется. Как только он будет создан, он не может быть изменен во время выполнения метода. Это позволяет фиксировать переменную в методе на время действия метода. Смотри ниже:

 public class FinalVariables { public final static void main(final String[] args) { System.out.println("Note how the key variable is changed."); someMethod("JAVA_HOME"); someMethod("ANT_HOME"); } } 

Конечные константы

 public double equation2Better(final double inputValue) { final double K = 1.414; final double X = 45.0; double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M); double powInputValue = 0; if (result > 360) { powInputValue = X * Math.sin(result); } else { inputValue = K * Math.sin(result); // <= Compiler error } 

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

Окончательные коллекции

В другом случае, когда мы говорим о Коллекциях, вам нужно установить их как не подлежащие регистрации.

  public final static Set VALID_COLORS; static { Set temp = new HashSet( ); temp.add(Color.red); temp.add(Color.orange); temp.add(Color.yellow); temp.add(Color.green); temp.add(Color.blue); temp.add(Color.decode("#4B0082")); // indigo temp.add(Color.decode("#8A2BE2")); // violet VALID_COLORS = Collections.unmodifiableSet(temp); } 

в противном случае, если вы не устанавливаете его как не подлежащее изменению:

 Set colors = Rainbow.VALID_COLORS; colors.add(Color.black); // <= logic error but allowed by compiler 

Конечные classы и конечные методы не могут быть расширены или перезаписаны соответственно.

РЕДАКТИРОВАТЬ: ДЛЯ АДРЕСА ЗАДАЧИ ОКОНЧАТЕЛЬНОГО КЛАССА В ОТНОШЕНИИ ЭНЦИПИРОВАНИЯ:

Есть два способа сделать окончательный class. Во-первых, использовать ключевое слово final в объявлении classа:

 public final class SomeClass { // . . . Class contents } 

Второй способ сделать окончательный class - объявить все его конструкторы как частные:

 public class SomeClass { public final static SOME_INSTANCE = new SomeClass(5); private SomeClass(final int value) { } 

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

 public class Test{ private Test(Class beanClass, Class stopClass, int flags) throws Exception{ // . . . snip . . . } } 

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

Поэтому вы должны пометить его окончательным, если вы неявно сделаете окончательный class, сделав его конструктором закрытым.

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

Если у вас есть внутренние (анонимные) classы, и метод должен получить доступ к переменной содержащего метода, вам необходимо, чтобы эта переменная была окончательной.

Кроме того, вы сказали, что это правильно.

Используйте ключевое слово final для переменной, если вы делаете эту переменную immutable

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

С выпуском java 8 у нас есть еще одна концепция, называемая « effectively final variable ». Не конечная переменная может входить в качестве конечной переменной.

локальные переменные, на которые ссылается выражение lambda, должны быть окончательными или эффективно конечными

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

До Java 7 вы не можете использовать неконфиденциальную локальную переменную внутри анонимного classа, но с Java 8 вы можете

Взгляните на эту статью

Очень простой ответ: у нас есть 3 случая с Final с переменными, Final with methods && Final с classами ..

1.Final с переменной: u не может присваивать эту переменную более одного раза ..

2.Final с методами: u не может переопределить этот метод.

3.Final с classами: u не может продлить какой-либо окончательный class

Прежде всего, последнее ключевое слово используется для создания переменной. Константа означает, что он не меняется. Например:

 final int CM_PER_INCH = 2.54; 

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

Если вы попытаетесь переопределить конечное значение, переменная – это то, что было объявлено первым. Например:

 final String helloworld = "Hello World"; helloworld = "A String"; //helloworld still equals "Hello World" 

Существует ошибка компиляции, которая выглядит примерно так:

 local variable is accessed from inner class, must be declared final 

Если ваша переменная не может быть объявлена ​​окончательной или если вы не хотите объявлять ее окончательной, попробуйте следующее:

 final String[] helloworld = new String[1]; helloworld[0] = "Hello World!"; System.out.println(helloworld[0]); helloworld[0] = "A String"; System.out.println(helloworld[0]); 

Это напечатает:

 Hello World! A String 
  • Как установить разделитель тысяч в Java?
  • Обнаружить и извлечь url из строки?
  • WebDriver открывает новую вкладку
  • o отобразить изображение
  • Как процитировать «* /» в JavaDocs
  • Добавление в ArrayList Java
  • вложенный тип не может скрывать закрытый тип
  • как установить заголовок без кэша весной mvc 3 по annotations
  • Какое правильное действие при закрытии окон в java / swing?
  • Как преобразовать String в Double в Java, используя определенную локаль?
  • Javadoc: package.html или package-info.java
  • Interesting Posts

    В чем разница между командами «su -s» и «sudo-s»?

    Является ли температура холостого хода 66 ° C для нормального процессора A10-6800K?

    Форматирование ReSharper: выравнивание равных операндов

    Распространяйте опцию через функцию (или Init) в Swift

    Что такое опция «sameq» или «same_quant» в FFmpeg? Означает ли это «такое же качество»?

    В Java, каков булевский «порядок операций»?

    constexpr не работает, если функция объявлена ​​внутри classа

    Конструктор перегрузки для classов Case Scala?

    Связь между Android Java и Phonegap Javascript?

    Как сделать дерево в Twig

    Вставка контактов в Android 2.2

    как получить div для случайного перемещения по странице (используя jQuery или CSS)

    Рассчитайте первое появление одного критерия на основании второго критерия

    Как я могу скомпилировать свой Perl-скрипт, чтобы он мог выполняться в системах без установленного perl?

    Является ли HTTP-заголовком Referer отправленным при переходе на страницу http с https-страницы?

    Давайте будем гением компьютера.