Почему ключевое слово 'final' так мало используется в отрасли? [закрыто]

14

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

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

Однако, просматривая некоторые исходные коды JDK, я никогда не сталкивался с этим ключевым словом ни для классов, ни для методов, ни для переменных. То же самое относится к различным системам, которые я должен был рассмотреть.

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

Аурелиен Рибон
источник
в микрооптимизации установка finalполей имеет ту же семантику, что и запись volatileполя, а затем для их чтения необходимо иметь изменчивую семантику чтения, это не всегда то, что вы хотите
ratchet freak
5
@ratchet: я думаю, что это больше о том, чтобы сделать ваши классы неизменяемыми, как в функциональном программировании.
Джонас
@Kwebble: Возможно, что еще важнее, отдельные экземпляры String неизменны.
MatrixFrog

Ответы:

9

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

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

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

Стивен Эверс
источник
2
Я даже имел в виду многие закрытые или защищенные члены некоторых классов JDK, которые явно «порождают один раз, никогда не переопределяют» объектные переменные. Особенно в свинг-пакете. Это идеальные кандидаты на «финал», поскольку замена на нулевой указатель может привести к ошибкам при использовании компонентов.
Аурелиен Рибон
1
@ Aurélien: Если вам от этого станет легче, многие классы в .NET Framework запечатаны, к большому удивлению некоторых пользователей, которые хотели бы расширить классы каркаса своими собственными функциями. Однако это ограничение может быть несколько смягчено с помощью методов расширения.
Роберт Харви,
1
Я думаю, что это больше об неизменности, чем о том, чтобы избежать расширения. Другими словами, использование finalполей, а не методов. Неизменяемые классы также могут быть предназначены для расширения.
Джонас
15

Проблема с использованием finalдля передачи того, что что-то доступно только для чтения, заключается в том, что оно действительно работает только для примитивных типов, таких как intи charт. Д. Все объекты в Java фактически упоминаются с использованием (своего рода) указателя. В результате, когда вы используете finalключевое слово для объекта, вы только говорите, что ссылка доступна только для чтения, сам объект по-прежнему изменчив.

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

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

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

В этом примере кажется очевидным, почему это не работает, но если someMethod(FancyObject)это большое и сложное замешательство, может последовать. Почему бы не избежать этого?

Это также часть стандартов кодирования Sun (или Oracle, я думаю, сейчас).

Гьян ака Гари Буйн
источник
1
Если бы было больше использования finalв классах API Java, большинство объектов было бы неизменным, как и во многих библиотеках Scala. Тогда создание полей объекта finalделает класс неизменным во многих случаях. Этот дизайн уже используется в BigDecimalи String.
Джонас
@Jonas Я прочитал вопрос, чтобы больше узнать о пункте 4 в ответе Шммда, поскольку он говорил: «поскольку люди могут легко видеть, что является переменными только для чтения», и отвечал соответственно. Возможно, я должен был включить это предположение в ответ.
Гьян ака Гари Буйн
Имейте в виду, что есть время, когда вы хотите переназначить параметр. В качестве примера - обрезка строкового параметра.
Стив Куо
@Steve Я обычно создаю новую переменную для назначения в этой ситуации.
Gyan aka Gary Buyn
1
@ Гэри, для меня, как минимум, очень редко, что ошибки / путаница вызваны переназначением параметра. Я бы предпочел иметь свободный от помех код и принять удаленный шанс переназначения параметра, вызывающего ошибку. Просто будьте осторожны при написании / изменении кода.
Стив Куо
4

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

Некоторые другие языки, такие как scala, значительно упрощают создание окончательных объявлений ( val ). В этих языках окончательные объявления могут быть более распространенными, чем переменные.

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

  1. финальные классы (JLS 8.1.1.2)
  2. окончательные поля (JLS 8.3.1.2)
  3. окончательные методы (JLS 8.4.3.3)
  4. окончательные переменные (JLS 4.12.4)
schmmd
источник
2

Начнем с того, что официальные соглашения по Java Code не поддерживают и не запрещают конкретное использование final. То есть разработчики JDK могут свободно выбирать способ, который они предпочитают.

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

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

Это также может немного увеличить JIT, и хотя оно очень ограничено, оно не может повредить

Рассуждения, как указано выше, скользкие. Преждевременная оптимизация может нанести вред; Дональд Кнут заходит так далеко, что называет его «корнем всего зла» . Не позволяйте этому заманить вас в ловушку. Напиши тупой код .

комар
источник
2

Недавно я обнаружил радость функции «Сохранить действия» в Eclipse IDE. Я могу заставить его переформатировать мой код, вставить недостающие @Overrideаннотации и сделать некоторые изящные вещи, такие как удаление ненужных скобок в выражениях или finalавтоматическое размещение ключевых слов везде при каждом нажатии ctrl + S. Я активировал некоторые из этих триггеров, и, мальчик, это очень помогает!

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

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

Оказалось, что чем меньше переменные меняются, тем меньше у меня проблем во время отладки. Сколько раз вы следили за значением некоторой переменной только для того, чтобы обнаружить, что она каким-то образом меняется, скажем, с 5 на 7? "Как, черт возьми, это может быть ?!" Вы спрашиваете себя и тратите следующие пару часов, входя и выходя из бесчисленных методов, чтобы выяснить, что вы допустили ошибку в своей логике. И чтобы исправить это, вам нужно добавить еще один флаг, пару условий и тщательно изменить некоторые значения здесь и там.

О, я ненавижу отладку! Каждый раз, когда я запускаю отладчик, я чувствую, что мое время истекает, и мне отчаянно нужно это время, чтобы хотя бы некоторые мои детские мечты сбылись! К черту отладку! finalОзначает, что больше нет таинственных изменений стоимости. Больше finals => меньше надуманных частей в моем коде => меньше ошибок => больше времени, чтобы делать хорошие вещи!

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


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

Андрей Андрей Листочкин
источник
1
Возможно, вы могли бы рассмотреть возможность изучения функциональных языков, таких как OCaml или F #. Эти языки, как правило, требуют гораздо меньше отладки, одной из причин является то, что по умолчанию все доступно только для чтения. Проще говоря, однажды назначенная переменная на функциональном языке не меняется.
Авель
1
Да, я знаю это, и время от времени я пишу некоторый ML-код - вот откуда я черпаю вдохновение :) Дело не в языке, который вы используете, а скорее в принципах и методах, которые вы применяете. С Haskell и doсистемой обозначений можно сделать все возможное :) Конечно, Java не лучший язык для написания в функциональном стиле, но, по крайней мере, он позволяет вам писать надежный код - и это то, что меня действительно волнует.
Андрей Андрей Листочкин