Использование "окончательного" модификатора, когда это применимо в java

В Java существует практика объявления каждой переменной (локальная или классная), параметр final если они действительно есть. Хотя это делает код намного более подробным, это помогает легко читать/захватывать код, а также предотвращает ошибки поскольку намерение четко обозначено.

Что вы думаете об этом и чем вы следуете?

Ответ 1

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

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

Во-первых, это выглядит неловко, чтобы увидеть много ключевых слов final в вашем коде, но довольно скоро вы перестанете замечать само слово и просто подумаете, что-thing-will-never-change- из-этого-на-point (вы можете взять его у меня;)

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

Для получения более подробной информации обратитесь к статье, связанной с ниже.

Заключительное слово В заключительном ключевом слове

Ответ 4

Модификатор 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);
 }

Некоторые ссылки:

Ответ 5

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

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

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

Ответ 6

Эффективная Java имеет элемент, который гласит: "Пользуйтесь неизменными объектами". Объявление полей в качестве окончательного помогает вам предпринять некоторые небольшие шаги к этому, но, конечно, гораздо больше для действительно неизменяемых объектов, чем это.

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

Ответ 7

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

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

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

Изменить: Как пояснение (и попытка отыграться назад), я не говорю, что не отмечайте константы как окончательные, я говорю, что не делайте таких вещей, как

public String doSomething() {
  final String first = someReallyComplicatedExpressionToGetTheString();
  final String second = anotherReallyComplicatedExpressionToGetAnother();

  return first+second;
}

Это просто делает код (по-моему) труднее читать.

Также стоит помнить, что финал all не позволяет переназначить переменную, это не делает ее неизменной или что-то в этом роде.

Ответ 8

Финал всегда должен использоваться для констант. Это даже полезно для короткоживущих переменных (в рамках одного метода), когда правила для определения переменной сложны.

Например:

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;

Ответ 9

Я использую final все время для атрибутов объекта.

Ключевое слово final имеет семантику видимости при использовании атрибутов объекта. В принципе, установка значения атрибута конечного объекта происходит до того, как возвращается конструктор. Это означает, что до тех пор, пока вы не позволите this ссылке избежать конструктора, и вы используете final для всех ваших атрибутов, ваш объект (по семантике Java 5) должен быть правильно сконструирован, и поскольку он также он может быть безопасно опубликован в других потоках.

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

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

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

Ответ 10

Мне нужно прочитать много кода для моей работы. Отсутствие конечных значений переменных экземпляра - одна из главных вещей, которые раздражают меня и затрудняют понимание кода. Для моих денег финал по локальным переменным вызывает больше беспорядка, чем ясность. Язык должен был быть разработан, чтобы сделать это дефолтом, но мы должны жить с ошибкой. Иногда это особенно полезно с циклами и определенным назначением с деревом if-else, но в основном это указывает на то, что ваш метод слишком сложный.

Ответ 11

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

Эффективная Java имеет целый элемент на этом (пункт 15), указывающий на подводные камни непреднамеренного наследования. Эффективно, если вы не разработали и не документировали свой класс для наследования, наследование от него может дать неожиданные проблемы (этот пункт дает хороший пример). Поэтому рекомендация заключается в том, что вы используете final для любого класса и/или метода, который не был наследован.

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

Ответ 12

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

Ответ 13

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

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

Ответ 14

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

Как только раздражение выходит за рамки разумного перехода на Scala, где аргументы окончательны по умолчанию.

Или вы всегда можете использовать инструменты моделирования кода, которые автоматически сделают это для вас. Все IDE имеют их реализованные или как плагины.

Ответ 15

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

В противном случае, я использую только, если это public/private static final type SOME_CONSTANT;

Ответ 16

Финал при использовании с переменными в Java обеспечивает замену константы на С++. Поэтому, когда конечная и статическая используются для переменной, она становится неизменной. В то же время мигрированные программисты на C++ очень довольны; -)

При использовании с опорными переменными он не позволяет повторно ссылаться на объект, хотя объект можно манипулировать.

Когда final используется с методом, он не позволяет перегружать метод подклассами.

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

Его следует использовать только для переменных, если вы не уверены, что значение переменной никогда не будет изменено. Также убедитесь, что вы соблюдаете соглашение кодирования, рекомендованное SUN.for например: final int COLOR_RED = 1; (Верхний регистр разделен символом подчеркивания)

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

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

Ответ 17

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

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

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

Но эй, это только мое мнение: -)

Ответ 18

Я установил Eclipse для добавления final во все поля и атрибуты, которые не изменены. Это отлично работает с помощью Eclipse "save actions", который добавляет эти окончательные модификаторы (между прочим) при сохранении файла.

Очень рекомендуется.

Отметьте мое сообщение в блоге Eclipse Save Actions.

Ответ 19

Даже для локальных переменных, зная, что оно объявлено окончательным, означает, что мне не нужно беспокоиться о замене ссылки позже. Это означает, что после отладки и я вижу эту переменную позже, я уверен, что она относится к одному и тому же объекту. Это одна вещь, о которой мне нужно беспокоиться, когда искал ошибку. Бонус заключается в том, что если 99% переменных объявлены окончательными, то несколько переменных, которые действительно являются переменными, выделяются лучше. Кроме того, последний позволяет компилятору найти более возможные глупые ошибки, которые в противном случае могут остаться незамеченными.

Ответ 20

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

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

Я пытаюсь обеспечить соблюдение правила, согласно которому все и все переменные должны быть окончательными. Гораздо проще ответить на вопрос: "Что это за переменная?" вопрос, если вам просто нужно найти инициализацию и быть уверенным, что это все.

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

Конечная переменная является просто хорошим способом для значений.

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

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

Ответ 21

Я уже некоторое время кодирую и использую финал, когда только могу. Сделав это некоторое время (для переменных, параметров метода и атрибутов класса), я могу сказать, что 90% (или более) моих переменных фактически являются окончательными. Я думаю, что преимущество НЕ иметь переменные, измененные, когда вы этого не хотите (я видел это раньше, и иногда это боль) платит за дополнительную типизацию и дополнительные "окончательные" ключевые слова в вашем коде.

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

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

Я также использую Collections.unmodifiable... для создания немодифицируемых списков, когда мне нужно.

Ответ 22

Использование анонимных локальных классов для прослушивателей событий и т.д. - общий шаблон в 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
        }
    };
}

Ответ 23

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

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

Что касается классов, только для некоторых классов инфраструктуры, я использовал последний класс.

IntelliJ IDEA предупреждает вас, если параметр функции записывается внутри функции. Итак, я прекратил использовать final для аргументов функции. Я также не вижу их в библиотеке Runtime java.

Ответ 24

Использование окончательного для констант настоятельно рекомендуется. Однако я бы не использовал его для методов или классов (или, по крайней мере, подумал об этом некоторое время), потому что он делает тестирование более сложным, если не невозможным. Если вы абсолютно должны сделать выпуск класса или метода, убедитесь, что этот класс реализует некоторый интерфейс, поэтому вы можете использовать mock тот же интерфейс.

Ответ 25

Маркировка окончательного класса также может привести к тому, что некоторые привязки методов происходят во время компиляции, а не во время выполнения. Рассмотрим ниже "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();
    }
}