LINUX.ORG.RU

Final Холивар

 ,


0

3

Всем хорошей пятницы!

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

Например:

void method() {
        final List<String> lst = new ArrayList<>();
        final Item item = create();
        /**
         * Do some work
         */
    }

Лично я считаю, что лучше с final писать. Коллега же считает, что в таких случаях final лишь замусоривает код и излишен. С другой стороны, тот же Блох советует все же их писать. Однако, если посмотреть на многие библиотеки, например, в Apache - там такой подход не применяется.

Речь идет именно о final в объявлении локальных переменных.

В общем, опрос такой: используете ли вы такой стиль?

Мне было бы интересно узнать ваше мнение!


Сам пишу и других заставляю. Лишняя проверка не помешает. У меня IDE сама подставляет final, когда переменную объявляешь. И вообще, политика ограничения всего, что можно, очень помогает

Deleted
()
Ответ на: комментарий от anonymous

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

mcgeek
()
Последнее исправление: mcgeek (всего исправлений: 1)

А можно предоставить сравнение листингов байт-кода с объявлением final и без? Есть большое подозрение, что именно в таком варианте (внутри метода и на объектах) разницы не будет. Так смысл?

yyk ★★★★★
()
Ответ на: комментарий от Deleted

Да, я с вами согласен в этом вопросе.

aarexer
() автор топика
Ответ на: комментарий от mcgeek

Ну т.е вы не используете final просто для локальных переменных, если не брать в виду работу с inner классами?

aarexer
() автор топика
Ответ на: комментарий от yyk

Вечером выложу, если до меня это кто-нибудь не сделает

aarexer
() автор топика
Ответ на: комментарий от mcgeek

Возможные ошибки должны быть покрыты тестами

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

Deleted
()
Ответ на: комментарий от Deleted

С final надежнее.

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

yyk ★★★★★
()
Ответ на: комментарий от Deleted

Не могли бы вы привести пример, где неиспользование final вредит? Ведь если переменная переинициализируется, то а) так надо логически, б) у нас плохой код, переменная используется для всего.

Имхо, если человек захочет переинициализировать переменную, то final его не остановит. Он его уберет. А это уже вопрос code review.

mcgeek
()

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

Но с другой стороны в языках, где это можно делать легко и непринуждённо, например в Kotlin — я всегда это делаю.

PS если уж решишь финализироваться — не забудь про параметры методов, они такие же локальные переменные и перед ними так же нужен final.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)

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

php-coder ★★★★★
()

ставлю когда сложный код и велика вероятность пересечения имен переменных (somethingSrc & somethingDst напр.) - с final меньше шансов в пьяном угаре ченить не туда присвоить, ну еще использую блоки {} и т.п.

Deleted
()

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

Leron ★★
()

Использую везде, где только можно: поля, локальные переменные, параметры функций. В идеале вкупе с глобальными @Nonnull, где можно. Что характерно, это часть Style Guide компании, и код без final ревью просто не пройдет. Но крестового const все равно не хватает, приходится где можно использовать Immutable* из-за этого.

mix_mix ★★★★★
()
Ответ на: комментарий от vzzo

TDD — чушь для хипстеров
хипстеров

Kent Beck, who is credited with having developed or 'rediscovered' the technique, stated in 2003 that TDD encourages simple designs and inspires confidence.

2003

чушь для хипстеров

Без комментариев.

mcgeek
()
Последнее исправление: mcgeek (всего исправлений: 1)
Ответ на: комментарий от mcgeek

хипстеры появились значительно раньше

anonymous
()

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

ThePretender
()

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

orm-i-auga ★★★★★
()

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

Он только этим руководствуется? А если бы в Java всё по-умолчанию было бы final и нужно было бы писать что-то типа var или mutable, чтобы добиться противоположного эффекта?

используете ли вы такой стиль?

Да, так меньше шансов допустить нелепую ошибку по невнимательности.

korvin_ ★★★★★
()

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

Смешно то, что реальную иммутабельность «final» не добавляет, к примеру final int[] values = {1,2,3} всё равно позволяет поменять значения массива. То же самое с классами. В Obj-C эту проблему решили на уровне библиотеки, к примеру есть иммутабельный NSString и его мутабельный субкласс NSMutableString, в жаве же даже это не уподобились сделать на уровне стандартной библиотеки. Поэтому объявляя переменную final имеем какую-то полумутабельную семантику.

В своём коде везде ставлю final где это возможно и других заставляю.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

В Obj-C эту проблему решили на уровне библиотеки, к примеру есть иммутабельный NSString и его мутабельный субкласс NSMutableString, в жаве же даже это не уподобились сделать на уровне стандартной библиотеки. Поэтому объявляя переменную final имеем какую-то полумутабельную семантику.

Э-м… В общем-то, кто тебе мешает реализовать это «решение» в виде собственных классов а ля MutableString, ImmutableArrayList и т.д? Собственно guava предоставляет классы иммутабельных коллекций.

korvin_ ★★★★★
()
Ответ на: комментарий от mcgeek

Не могли бы вы привести пример, где неиспользование final вредит?

Вы не знаете вредит ли оно пока ваша программа не гавкнется. Отсутствие иммутабельной семантики при объявлении переменной ведёт к таким же печальным последствиям, как и в Python: пока вы не переберёте ВСЕ 100% вариантов выполнения вашей программы в рантайме там могут спокойно годами жить опечатки. Типичные случаи неинициализированная переменная или перезатёртая по ошибке.

Dendy ★★★★★
()
Ответ на: комментарий от TheAnonymous

Вот так нельзя:

int sum = 0;
list.forEach(e -> { sum += e.length(); });


А вот так можно:
int[] sum = {0};
list.forEach(e -> { sum[0] += e.length(); });

TheAnonymous ★★★★★
()
Ответ на: комментарий от korvin_

В общем-то, кто тебе мешает реализовать это «решение» в виде собственных классов

Идея имеет смысл. Но тогда программы на жаве станут ещё многословнее и монструознее. Делить классы на два и кастировать одно к другому. И что делать с проблемой ромбовидного наследования? Всё-таки хотелось бы элегантного решения на уровне языка, но имеем что имеем.

Dendy ★★★★★
()

А в Scala вообще стараются обходиться константными объектами. Переменные там используются крайне редко.

LongLiveUbuntu ★★★★★
()

Ну и зачем ограничивать тему явой? В C, C++ то же самое.

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

Да, еще лучше было бы иметь иммутабельность по умолчанию. Привет, rust.

anonymous
()
Ответ на: комментарий от korvin_

Э-м… В общем-то, кто тебе мешает реализовать это «решение» в виде собственных классов а ля MutableString, ImmutableArrayList и т.д?

Здравый смысл?

Собственно guava предоставляет классы иммутабельных коллекций.

Это не то, там иммутабельность проверяется во время выполнения, т.е. кидается исключение при попытке модифицировать коллекцию. А надо на уровне типов — отдельно ImmutableCollection и MutableCollection, например. В Java уже этого не изменить, видимо в 1990-м году такие концепции не были очевидны. Но можно взять языки вроде Kotlin, там это сделали, оставив совместимость с Java.

Legioner ★★★★★
()
Ответ на: комментарий от unt1tled

Али скила не хватает?

Кто такой Али и что он сделал для джавы в своей жизни ?

anonymous
()
Ответ на: комментарий от robotron5

Аки дети малые: «лучше», «хуже»... пиздуйте учить java memory model

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

anonymous
()
Ответ на: комментарий от Dendy

всё равно позволяет поменять значения массива

Так вроде же final - это про ссылку. То бишь values = {1, 2, 3} говорит о том, что values ссылается на некую область в памяти (в нашем случае это массив), значение в области памяти может меняться, но мы всегда будем ссылаться туда. Равно как и final MyObject object не делает объект иммутабельным, если у него есть сеттеры - мы можем менять этот объект.

Jefail ★★★★
()
Ответ на: комментарий от Dendy

пока вы не переберёте ВСЕ 100% вариантов выполнения вашей программы

Разве это не должно покрываться тестами? Ну и final никак не защищает от изменения элементов массива или списка, например.

mcgeek
()

Используя для доступа из анонимных классов и для некоторых полей, которые никогда точно не поменяются (всякие read-only DTO и константы). Раньше на одном проекте заставляли все обносить final и еще и скобки после if/for/etc переносить на новую строку. Больные.

spoilt ★★★
()

final в объявлении локальных переменных.

когда у компьютеров было по 128 МБ памяти, да так можно было делать

однако сейчас 2017

все пишут объемный код который просто читать, по функции на каждый чих и по классу на каждый объект

так вот логика писания кода 2017 года где каждая функция выполняется доли секунды-а как известно все локальные переменные удаляютсяв конце функции
так вот- смысл финал в 2017 не имеет никакого смысла

чтото на уровне не ставить ; в конце условий и после } в Си чтоб сохранить 1 такт процессора(на восьмияддерниках по 4ггц,ага)

lwx51033
()
Ответ на: комментарий от Dendy

Делить классы на два и кастировать одно к другому

А в Obj-C как-то по-другому?

И что делать с проблемой ромбовидного наследования?

В языке, где нет множественного наследования реализация? Ничего.

Всё-таки хотелось бы элегантного решения на уровне языка, но имеем что имеем.

То, что ты описал в Obj-C не является «элегантным решением на уровне языка», а просто библиотекой классов.

korvin_ ★★★★★
()
Ответ на: комментарий от Legioner

Здравый смысл?

Т.е. в Obj-C он ему не мешает, а тут вдруг начал мешать?

Это не то, там иммутабельность проверяется во время выполнения

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

В Java уже этого не изменить

Не изменить чего? В стандартной библиотеке только mutable (не считая String'ов и прочих Integer'ов), immutable реализовывай как хочешь.

Но можно взять

и перестать пороть пургу. Для начала.

korvin_ ★★★★★
()
Ответ на: комментарий от robotron5

Аки дети малые: «лучше», «хуже»... пиздуйте учить java memory model

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

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

Т.е. в Obj-C он ему не мешает, а тут вдруг начал мешать?

В Obj-C стандартная библиотека более адекватная: там разделены мутабельные и иммутабельные типы, например NSArray и NSMutableArray.

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

Только идиот будет переписывать стандартные классы коллекций. По крайней мере если стандартные хоть сколько-нибудь юзабельны. А Java-оские таки юзабельны, хотя и далеки от идеала.

и перестать пороть пургу. Для начала.

Было бы неплохо.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

В Obj-C стандартная библиотека более адекватная: там разделены мутабельные и иммутабельные типы, например NSArray и NSMutableArray.

Так в Java то же самое: в стандартной библиотеке есть мутабельный ArrayList, а иммутабельный бери откуда хочешь, хоть сам реализуй, делов-то.

Только идиот будет переписывать стандартные классы коллекций

Так их никто и не переписывал.

По крайней мере если стандартные хоть сколько-нибудь юзабельны

При чём тут «юзабельность»? Речь шла о контракте mutable/immutable.

Было бы неплохо.

Я верю, что ты сможешь.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от korvin_

обсуждение семантики языка

чего-чего? Ну ладно у тебя хаскель на аватарке тебе простительно... Я лишь сказал что топикстартер со своим коллегой два некомпетентных барана судя по фразам,- «Лично я считаю, что лучше с final писать» и «final лишь замусоривает код и излишен», которые понятия не имеют что такое final и для чего он нужен) А final был введен в язык с конкретной целью, а чтоб узнать с какой нужно посмотреть JMM.

robotron5
()
Ответ на: комментарий от mcgeek

Ну и final никак не защищает от изменения элементов массива или списка, например.

Про то и речь (-: В C++, к примеру, добавляя const к ссылке или второй const к указателю отсекаешь мутабельные методы. Интересна причина, по которой в жаве решили не отделять мутабельные методы.

Dendy ★★★★★
()
Ответ на: комментарий от lwx51033

когда у компьютеров было по 128 МБ памяти, да так можно было делать

Каким образом final для локальных переменных меняет поведение в рантайме, разве это не просто защита на этапе компиляции?

Dendy ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.