В Java существует практика объявления каждой переменной (локальной или классовой) параметром final, если они действительно есть.
Хотя это делает код более подробным, это помогает облегчить чтение / понимание кода, а также предотвращает ошибки, поскольку намерение четко обозначено.
Что вы думаете по этому поводу и за чем следите?
Я могу понять, если людям не нравится, когда их код загроможден финалами. Но это проблема, которую мог бы решить хороший редактор: bugs.eclipse.org/bugs/show_bug.cgi?id=409379
связанные stackoverflow.com/questions/154314/when-should-one-use-final




Я никогда не был в ситуации, когда наличие последнего ключевого слова для переменной удерживало меня от ошибки, поэтому на данный момент я думаю, что это гигантская трата времени.
Если для этого нет реальной причины (например, если вы хотите указать конкретное положение о том, что эта переменная является окончательной), я бы предпочел не делать этого, поскольку я считаю, что это делает код менее читаемым.
Если, однако, вы не обнаружите, что код становится труднее читать или дольше писать, то обязательно сделайте это.
Редактировать: В качестве пояснения (и попытки вернуть голоса против) я не говорю, что константы не помечаются как окончательные, я говорю, что не делайте таких вещей, как:
public String doSomething() {
final String first = someReallyComplicatedExpressionToGetTheString();
final String second = anotherReallyComplicatedExpressionToGetAnother();
return first+second;
}
Это просто затрудняет чтение кода (на мой взгляд).
Также стоит помнить, что все final не дает вам переназначить переменную, он не делает ее неизменной или что-то в этом роде.
Переворачивая утверждение с ног на голову: я был в множество ситуаций, когда нет с использованием final (и неизменяемых объектов в целом) оказал существенное влияние на количество и влияние ошибок.
Я сторонник неизменяемых объектов, я просто никогда не был в ситуации, когда пометка неизменяемого объекта final мне помогла.
Я согласен с тем, что мы не должны использовать final для локальных переменных и параметров метода, это делает код намного менее читаемым.
@ChrisVest, возможно, ваши функции слишком длинные
Вам действительно нужно понять полное использование ключевого слова final, прежде чем использовать его. Он может применяться к переменным, полям, методам и классам и по-разному влияет на них.
Я бы порекомендовал ознакомиться со статьей, ссылки на которую приведены ниже, для получения дополнительных сведений.
Я почти не использую final для методов или классов, потому что мне нравится позволять людям переопределять их.
В противном случае я использую только final, если это public/private static final type SOME_CONSTANT;
Хм .. отредактировано в одном месте .. все же сказано, наконец, во второй строке ;-)
Разрешение людям переопределять значения - один из самых больших источников сюрпризов и трудных для понимания ошибок.
В Effective Java есть пункт «Отдавать предпочтение неизменяемым объектам». Объявление полей как final поможет вам сделать несколько небольших шагов в этом направлении, но, конечно, действительно неизменяемые объекты - это гораздо больше, чем это.
Если вы знаете, что объекты неизменяемы, их можно использовать для чтения среди множества потоков / клиентов, не беспокоясь о синхронизации, и легче понять, как работает программа.
осторожно - окончательный и неизменный - это совершенно разные понятия. Легко иметь конечный изменяемый объект - final относится к ссылке, изменяемость - к экземпляру объекта. последний человек olaf = новый человек (); olaf.setName («Олаф»);
Точно: неизменяемые объекты - это одно, неизменяемые ссылки (т.е. final) - это совсем другое.
Но они тесно связаны, поскольку вы можете, объявив поле Person.name как final (и объявив класс final и ...), сделать объект Person окончательным. Однако это не так просто, как просто выполнить "final Person" ...
Это также не имеет значения для локальных переменных (параметры являются локальными). Он применяется только к переменным класса, поэтому лишь частично решает вопрос.
Я думаю, все дело в хорошем стиле программирования. Конечно, вы можете писать хорошие, надежные программы, не используя где-либо множество модификаторов final, но если подумать ...
Добавление final ко всем вещам, которые изменяются в не следует, просто сужает возможности того, что вы (или следующий программист, работающий над вашим кодом) неверно истолкуете или будете неправильно использовать мыслительный процесс, результатом которого стал ваш код. По крайней мере, это должно прозвучать, когда они теперь захотят изменить вашу ранее неизменную вещь.
Поначалу кажется неловким видеть много ключевых слов final в вашем коде, но довольно скоро вы перестанете замечать само слово и просто подумаете, эта вещь никогда не изменится с этого момента (вы можете взять его у меня ;-)
Я считаю это хорошей практикой. Я не использую его постоянно, но когда есть возможность и имеет смысл маркировать что-то final, я это сделаю.
Вместо использования ключевого слова final для параметров вы можете использовать инструмент статического анализа, такой как FindBugs, чтобы требовать, чтобы переменные параметра не переназначались. Таким образом, вы устраняете синтаксическую нагрузку и можете обеспечить ее соблюдение с помощью проверки FindBugs в инструменте непрерывной интеграции.
@Timo Это сработает, но у него есть обратная сторона: это нужно проверять после проверки, а не пока разработчик работает над кодом. Для final компилятор, очевидно, не позволит вам продолжить, если вы сделаете ошибку.
@ Майк, согласен. Я люблю FindBugs и использую его неукоснительно, но когда есть функция языка и поддержка компилятора ... используйте ее! Да, я думаю, что final повсюду уродлив, и когда они наконец сделают несовместимую перезапись Java, я надеюсь, что по умолчанию все будет окончательно.
Eclipse имеет возможность добавлять final, когда это возможно (переменные, которые не изменяются) при сохранении.
+1 Обожаю final. В 98% случаев это не имеет значения, это незначительное неудобство в% 1 случаях, но 1% времени спасает меня от того, чтобы сделать что-то глупое или непреднамеренное, оно того стоит.
вот случай, когда использование final усложняет ваш код ... stackoverflow.com/questions/9350605/…
@BertF Да, я всегда позволяю Eclipse добавлять модификаторы final повсюду, когда я "очищаю ..." свой код. Везде означает даже в блоках catch (), и, как сказано, вы их не заметите через некоторое время. Конечно, если бы я создал язык, final был бы по умолчанию, а var или modifiable было бы необязательным ключевым словом.
@MaartenBodewes Забавно, теперь на JVM работает язык, где по умолчанию используется final: Котлин
@Joschua Поверьте мне, я с большим интересом слежу за Котлином. Он по-прежнему содержит целочисленные переполнения и тому подобное, но в остальном это кажется шагом в правильном направлении.
"эта-вещь-никогда-никогда не изменится с этой точки" жаль, что она не работает таким образом с изменяемыми объектами.
Особенно, когда вы сотрудничаете, это ооочень полезно! Часто, когда я не уверен, что делает переменная / поле, или если оно где-то видоизменилось, я просто вставляю перед ним final и позволяю компилятору разобраться в этом: P Если он компилируется, отлично! Оставьте его, чтобы его было легче прочитать следующему человеку. Если нет, то, по крайней мере, вы точно знаете все критические моменты, в которых он используется.
Final при использовании с переменными в Java обеспечивает замену константы в C++. Поэтому, когда для переменной используются final и static, она становится неизменной. В то же время очень довольны мигрировавшие программисты на C++ ;-)
При использовании со ссылочными переменными он не позволяет вам повторно ссылаться на объект, хотя объектом можно манипулировать.
Когда final используется с методом, он не позволяет переопределить метод подклассами.
Как только использование становится очень ясным, его следует использовать с осторожностью. В основном это зависит от дизайна, поскольку использование final в методе не поможет полиморфизму.
Его следует использовать для переменных только тогда, когда вы чертовски уверены, что значение переменной никогда не будет / не должно изменяться. Также убедитесь, что вы следуете соглашению о кодировании, рекомендованному SUN. Например: final int COLOR_RED = 1; (Верхний регистр разделен подчеркиванием)
Со ссылочной переменной используйте ее только тогда, когда нам нужна неизменная ссылка на конкретный объект.
Что касается читабельности, следует отметить, что комментарии играют очень важную роль при использовании модификатора final.
Вероятно, это потому, что вы заявляете, что должны делать его ТОЛЬКО при XYZ. Другие считают, что лучше сделать ВСЕ окончательным, если в этом нет необходимости.
Это вовсе не замена ключевому слову const в C++. -1.
Использование анонимных локальных классов для прослушивателей событий, и это распространенный шаблон в Java. Наиболее распространенное использование ключевого слова final - убедиться, что переменные в области видимости доступны для четного слушателя.
Однако, если вы обнаружите, что вам нужно поместить в свой код много заключительных операторов. Это может быть хорошим намеком на то, что вы делаете что-то не так.
В опубликованной выше статье приводится такой пример:
public void doSomething(int i, int j) {
final int n = i + j; // must be declared final
Comparator comp = new Comparator() {
public int compare(Object left, Object right) {
return n; // return copy of a local variable
}
};
}
Я использую его для констант внутри и вне методов.
Я только иногда использую его для методов, потому что не знаю, НЕ захочет ли подкласс переопределить данный метод (по каким-либо причинам).
Что касается классов, то только для некоторых классов инфраструктуры я использовал final class.
IntelliJ IDEA предупреждает вас, если параметр функции записан внутри функции. Итак, я перестал использовать final для аргументов функции. Я также не вижу их внутри библиотеки времени выполнения Java.
Настоятельно рекомендуется использовать final для констант. Однако я бы не стал использовать его для методов или классов (или, по крайней мере, подумать об этом какое-то время), потому что это усложняет тестирование, если не делает его невозможным. Если вам абсолютно необходимо сделать класс или метод окончательным, убедитесь, что этот класс реализует некоторый интерфейс, чтобы вы могли иметь насмехаться, реализующий тот же интерфейс.
Это не усложняет тестирование, потому что вы в любом случае должны использовать интерфейсы.
Модификатор final, особенно для переменных, является средством заставить компилятор применять соглашение, которое в целом является разумным: убедитесь, что переменная (локальная или экземплярная) назначается ровно один раз (не больше и не меньше). Убедившись, что переменная определенно назначена перед ее использованием, вы можете избежать распространенных случаев NullPointerException:
final FileInputStream in;
if (test)
in = new FileInputStream("foo.txt");
else
System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned
Предотвращая присвоение переменной более одного раза, вы препятствуете чрезмерной области видимости. Вместо этого:
String msg = null;
for(int i = 0; i < 10; i++) {
msg = "We are at position " + i;
System.out.println(msg);
}
msg = null;
Вам предлагается использовать это:
for(int i = 0; i < 10; i++) {
final String msg = "We are at position " + i;
System.out.println(msg);
}
Некоторые ссылки:
Короче говоря, вы можете использовать от final до сделать Java более выраженной.
На самом деле «Убедившись, что переменная определенно назначена перед ее использованием, вы можете избежать распространенных случаев исключения NullPointerException:» это неверно, 'final' здесь не имеет значения, компилятор знает и жалуется на переменную 'in', возможно в приведенном примере имеет значение NULL.
@nyholku Вы правы, в Java локальные переменные должны быть обязательно назначены перед использованием, также без final. Но для полей нужен финал. В несколько более сложном примере, где «in» - это переменная экземпляра класса, а if / else находится в конструкторе, вам нужен финал, чтобы сигнализировать о проблеме. Кроме того, также для локальных переменных есть некоторое значение в окончательном IMO, поскольку оно не позволяет неаккуратному программисту «исправить» ошибку компиляции о том, что «in», возможно, не назначено, добавив «= null» к его объявлению. Другими словами, по моему опыту, конечные переменные сокращают использование null.
Я все время использую final для атрибутов объектов.
Ключевое слово final имеет семантику видимости при использовании в атрибутах объекта. По сути, установка значения атрибута final объекта происходит до того, как конструктор вернется. Это означает, что до тех пор, пока вы не позволяете ссылке this ускользать из конструктора и используете final для атрибутов все, ваш объект (в соответствии с семантикой Java 5) гарантированно будет правильно сконструирован, а поскольку он также является неизменяемым, он может быть безопасно опубликовано в других темах.
Неизменяемые объекты - это не только безопасность потоков. Они также значительно упрощают рассуждения о переходах между состояниями в вашей программе, потому что пространство, в котором изменяется может, преднамеренно и, при последовательном использовании, полностью ограничивается только тем, что изменяет должен.
Иногда я также делаю методы финальными, но не так часто. Я редко заканчиваю уроки. Обычно я делаю это потому, что мне это не нужно. Обычно я не особо использую наследование. Вместо этого я предпочитаю использовать интерфейсы и композицию объектов - это также поддается дизайну, который, как мне кажется, часто легче проверить. Когда вы кодируете интерфейсы вместо конкретных классов, тогда вы не можете использовать необходимость для использования наследования, когда вы тестируете, как есть, с такими фреймворками, как jMock, гораздо проще создавать макетные объекты с интерфейсами, чем с конкретными классами.
Думаю, мне следует сделать большинство своих занятий финальными, но я еще не вошел в привычку.
Для работы мне приходится читать много кода. Отсутствие final в переменных экземпляра - одна из главных вещей, которые меня раздражают и излишне затрудняют понимание кода. На мой взгляд, final по локальным переменным вызывает больше беспорядка, чем ясности. Язык должен был быть разработан так, чтобы сделать это по умолчанию, но мы должны жить с ошибкой. Иногда это полезно, особенно с циклами и определенным присваиванием с деревом if-else, но в основном это указывает на то, что ваш метод слишком сложен.
Почему бы не использовать инструмент, уменьшающий беспорядок?
@Pacerier Как редактор, искажающий код?
Зацикливаться на:
Подумайте, но используйте разумно:
Игнорируйте, если не чувствуете себя анальным:
В большинстве случаев, когда я вижу локальную переменную без последнего слова перед ней и ее нельзя использовать там, она говорит мне, что мне, вероятно, следует извлечь какой-то код в новом методе, который возвращает желаемое значение, которое я сделаю окончательным. Случаи, когда это не применимо, - это когда я использую некоторые потоки или мне нужно попробовать поймать его.
Я никогда не использую их для локальных переменных, в дополнительной многословности нет смысла. Даже если вы не думаете, что переменная должна быть переназначена, это не будет иметь большого значения для следующего человека, изменяющего этот код, который думает иначе, и, поскольку код изменяется, любая первоначальная цель сделать его окончательным может больше не действовать. Если это просто для ясности, я считаю, что это не удается из-за негативных последствий многословия.
Практически то же самое применимо и к переменным-членам, поскольку они дают мало преимуществ, за исключением случая констант.
Это также не имеет отношения к неизменяемости, поскольку лучший индикатор неизменности чего-либо - это то, что оно задокументировано как таковое и / или не имеет методов, которые могут изменить объект (это, наряду с окончательным окончанием класса, является единственным способом гарантировать, что он неизменен).
Но это только мое мнение :-)
Я настроил Eclipse, чтобы добавить final для всех полей и атрибутов, которые не изменяются. Это отлично работает с использованием Eclipse «save actions», который добавляет эти последние модификаторы (среди прочего) при сохранении файла.
Настоятельно рекомендуется.
Ознакомьтесь с мой пост в блоге из Eclipse Save Actions.
Очевидно, что окончательный следует использовать для констант и для обеспечения неизменяемости, но есть еще одно важное применение методов.
В Эффективная Java есть целый пункт по этому поводу (Правило 15), указывающий на подводные камни непреднамеренного наследования. Фактически, если вы не спроектировали и не задокументировали свой класс для наследования, наследование от него может вызвать неожиданные проблемы (этот элемент является хорошим примером). Поэтому рекомендуется использовать окончательный для любого класса и / или метода, от которых не предполагалось наследовать.
Это может показаться суровым, но в этом есть смысл. Если вы пишете библиотеку классов для использования другими, вы не хотите, чтобы они унаследовали от вещей, которые не были предназначены для этого - вы заблокируете себя в конкретной реализации класса для обратной совместимости. Если вы пишете код в команде, ничто не может помешать другому члену команды удалить окончательный, если это действительно необходимо. Но ключевое слово заставляет их задуматься о том, что они делают, и предупреждает, что класс, от которого они наследуют, не предназначен для этого, поэтому им следует быть особенно осторожными.
Final всегда следует использовать для констант. Это даже полезно для недолговечных переменных (в рамках одного метода), когда правила определения переменной сложны.
Например:
final int foo;
if (a)
foo = 1;
else if (b)
foo = 2;
else if (c)
foo = 3;
if (d) // Compile error: forgot the 'else'
foo = 4;
else
foo = -1;
Маркировка класса final также может привести к привязке некоторых методов во время компиляции, а не во время выполнения. Рассмотрим "v2.foo ()" ниже - компилятор знает, что B не может иметь подкласс, поэтому foo () не может быть переопределен, поэтому реализация для вызова известна во время компиляции. Если класс B НЕ помечен как окончательный, то возможно, что фактический тип v2 - это некоторый класс, который расширяет B и переопределяет foo ().
class A {
void foo() {
//do something
}
}
final class B extends A {
void foo() {
}
}
class Test {
public void t(A v1, B v2) {
v1.foo();
v2.foo();
}
}
Еще одно предостережение заключается в том, что многие люди путают final с тем, что содержимое переменной экземпляра не может измениться, а не что ссылка не может измениться.
И этот пост - яркое тому доказательство.
final можно изменить через setter ().
Я довольно категоричен в отношении объявления всех возможных переменных final. Сюда входят параметры метода, локальные переменные и, в редких случаях, поля объекта значений. У меня есть три основные причины для объявления финальных переменных повсюду:
Однако я считаю, что классы и методы final не так полезны, как ссылки на переменные final. Ключевое слово final при использовании с этими объявлениями просто создает препятствия для автоматического тестирования и использования вашего кода способами, о которых вы даже не догадывались.
Переменные final и параметры метода не влияют на производительность, поскольку они не выражаются в байт-коде.
переменная: = латинский: varius> разный> изменяемый
Даже для локальных переменных знание того, что он объявлен как final, означает, что мне не нужно беспокоиться о том, что ссылка будет изменена позже. Это означает, что при отладке, и я вижу эту переменную позже, я уверен, что она ссылается на один и тот же объект. Это на одну вещь меньше, о чем мне нужно беспокоиться при поиске ошибки. Бонус в том, что если 99% переменных объявлены окончательными, то несколько переменных, которые действительно являются переменными, выделяются лучше. Кроме того, финал позволяет компилятору найти еще несколько возможных глупых ошибок, которые в противном случае могли бы остаться незамеченными.
Думаю, для аргументов они не нужны. Мостли они просто повредили читабельности. Переназначать переменную аргумента настолько безумно глупо, что я должен быть вполне уверен, что их в любом случае можно рассматривать как константы.
Тот факт, что Eclipse окрашивает конечный красный цвет, упрощает обнаружение объявлений переменных в коде, что, как мне кажется, в большинстве случаев улучшает читаемость.
Я пытаюсь обеспечить соблюдение правила, согласно которому все без исключения переменные должны быть окончательными, если нет крайней веской причины не делать этого. Намного легче ответить на вопрос «что это за переменная?» вопрос, если вам просто нужно найти инициализацию и быть уверенным, что это она.
Я действительно довольно нервничаю из-за неокончательных переменных сейчас. Это как разница между ножом, висящим на нитке над головой, или просто кухонным ящиком ...
Последняя переменная - это просто хороший способ пометить значения.
Неокончательная переменная связана с частью алгоритма, подверженного ошибкам.
Одна приятная особенность заключается в том, что, когда возможность использовать переменную для алгоритма не рассматривается большую часть времени, решение состоит в том, чтобы вместо этого написать метод, который обычно значительно улучшает код.
Я уже некоторое время кодирую и использую final, когда могу. Сделав это некоторое время (для переменных, параметров метода и атрибутов класса), я могу сказать, что 90% (или более) моих переменных фактически являются окончательными. Я думаю, что преимущество НЕ изменять переменные, когда вы этого не хотите (я видел это раньше, и иногда это больно), окупается за дополнительный набор текста и дополнительные «финальные» ключевые слова в вашем коде.
При этом, если бы я разработал язык, я бы сделал каждую переменную окончательной, если она не была изменена каким-либо другим ключевым словом.
«Я не часто использую final для классов и методов, - подумал я. Это более или менее сложный выбор дизайна, если только ваш класс не является служебным (в этом случае у вас должен быть только один частный конструктор).
Я также использую Collections.unmodifiable ... для создания неизменяемых списков, когда мне нужно.
Похоже, один из самых больших аргументов против, использующих ключевое слово final, - это то, что «это не нужно», и это «тратит впустую место».
Если мы признаем многие преимущества «final», как указано во многих замечательных публикациях здесь, и при этом признаем, что это требует больше ввода и места, я бы сказал, что Java должна была сделать переменные «final» по умолчанию и потребовать, чтобы все было помечено « mutable ", если кодировщик этого хочет.
Странно тогда называть это переменной, не так ли?
Есть тысячи английских слов на выбор.
Это потрясающе. Против final нет аргументов, кроме «слишком долго писать», «делает код более неуклюжим». В пользу final есть несколько аргументов. И мы можем автоматически добавлять его при сохранении, если вы не хотите вводить его вручную.
Выбор типа final для каждого параметра в каждом методе вызовет сильное раздражение как у программистов, так и у считывателей кода.
Как только раздражение выходит за рамки разумного, переключитесь на Scala, где аргументы по умолчанию являются окончательными.
Или вы всегда можете использовать инструменты стилизации кода, которые сделают это автоматически. Во всех IDE они реализованы или в виде плагинов.
Это может привести к религиозному спору. Кому-то это нравится, кому-то это не нравится. Мне нравятся поля final, но не конечные локальные переменные, если они не нужны, не уверен, что это полностью рационально. Не уверен, что будет и голос "против". Я согласен с Алексом Миллером. ;)