Чому "остаточне" ключове слово використовується так мало в галузі? [зачинено]


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)велика і складна плутанина може настати. Чому б не уникнути цього?

Він також є частиною стандартів кодування для Сонця (або зараз я думаю, Oracle).


1
Якщо finalв класах Java API було більше використання , більшість об'єктів були незмінні, як і у багатьох бібліотеках Scala. Тоді створення об’єктних полів finalробить клас незмінним у багатьох випадках. Ця конструкція вже використовується в BigDecimalта String.
Йонас

@Jonas Я прочитав питання, щоб дізнатися більше про пункт 4 у відповіді schmmd, оскільки він сказав "оскільки люди можуть легко бачити, що є змінними лише для читання", і відповів відповідно. Можливо, я мав би включити це припущення у відповідь.
Gyan aka Gary Buyn

Майте на увазі, що настає час, коли ви хочете перепризначити параметр. Як приклад - обрізка параметра рядка.
Стів Куо

@Steve Я зазвичай створюю нову змінну, яку потрібно призначити в цій ситуації.
Gyan aka Gary Buyn

1
@Gary, як мінімум, дуже рідко буває, що помилки / плутанина викликаються перепризначенням параметра. Я набагато скоріше маю безладний код і приймаю віддалений шанс перепризначення параметра, що викликає помилку. Будьте обережні при написанні / зміні коду.
Стів Куо

4

Я згоден, що finalключове слово покращує читабельність. Це значно полегшує розуміння того, коли об’єкт непорушний. Однак у Java це надзвичайно багатослівно, особливо (на мій погляд) при використанні параметрів. Це не означає, що люди не повинні використовувати його, оскільки він є багатослівним, а навпаки, вони не використовують його, оскільки він є багатослівним.

Деякі інші мови, наприклад, scala, значно полегшують складання остаточних оголошень ( val ). У цих мовах підсумкові декларації можуть бути більш поширеними, ніж змінні.

Зауважте, що у кінцевому слові існує багато різних варіантів використання. Ваша публікація охоплює елементи 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)

2

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

Я не можу прочитати їхню думку, але мені, finalнаголос, було те, чи слід використовувати чи ні. Справа в тому, чи є у мене достатньо часу, щоб докладно зосередитись на коді чи ні .

  • Скажімо, в одному з моїх проектів ми могли дозволити собі витратити в середньому день приблизно 100 рядків коду. У цьому проекті у мене було чітке сприйняття finalяк сміття, яке просто затьмарює речі, які вже досить чітко виражені в коді. Схоже, розробники JDK теж потрапляють до цієї категорії.
     
    З іншого боку, це було абсолютно протилежно в іншому проекті, де ми витрачали середню годину на 100 рядків коду. Там я опинився, finalяк стріляв як пістолет-машинка у своєму власному та чужому коді - просто тому, що це був найшвидший спосіб виявити наміри хлопця, який написав це перед мною, і, аналогічно, якнайшвидший спосіб повідомити про свій власний намір хлопець, який пізніше буде працювати над моїм кодом.

Це також може дати невеликий приріст JIT, і хоча це дуже обмежений, він не може нашкодити

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


2

Нещодавно я виявив радість від функції "Зберегти дії" в IDE Eclipse. Я можу змусити її переформатувати код, вставити пропущені @Overrideанотації та виконувати деякі чудові речі, як-от видалити непотрібні дужки в виразах або finalавтоматично розміщувати ключове слово скрізь автоматично, коли я натискаю ctrl + S. Я активував деякі з цих тригерів і, хлопче, це дуже допомагає!

Виявилося, що багато з цих тригерів діють як швидка перевірка правильності для мого коду.

  • Я мав намір замінити метод, але анотація не з’явилася, коли я потрапив ctrl + s? - можливо, я десь накрутив типи параметрів!
  • Деякі дужки були вилучені з коду при збереженні? - можливо, це логічне вираження занадто складно для програміста, щоб швидко його обійти. Інакше навіщо я додавати ці дужки в першу чергу?
  • Цей параметр або локальна змінна не є final. Є чи у змінити його значення?

Виявилося, що менша кількість змінних змінює меншу кількість проблем у мене на час налагодження. Скільки разів ви слідкували за значенням змінної лише для того, щоб виявити, що вона якось змінюється від скажімо 5 до 7? "Як чорт може бути ?!" Ви запитаєте себе і витрачаєте наступні пару годин, крокуючи та вичиняючи незліченну кількість методів, щоб з’ясувати, що ви помилилися у своїй логіці. А щоб виправити це, вам потрібно додати ще один прапор, пару умов і обережно змінити деякі значення тут і там.

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

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


Побачення всіх цих finalкодів спочатку дещо відволікає і вимагає часу, щоб звикнути. Деякі мої товариші по команді все ще дуже здивовані, побачивши так багато finalключових слів. Я хотів би, щоб в IDE було встановлено спеціальне забарвлення синтаксису для нього. Я був би радий переключити його на деякий відтінок сірого (як анотації), щоб вони не надто відволікали під час читання коду. Наразі Eclipse має окремий колір для returnвсіх інших ключових слів, але не дляfinal .


1
Можна, можливо, розглянути такі функціональні мови, як OCaml або F #. Ці мови, як правило, вимагають набагато меншої налагодження, одна з причин полягає в тому, що все використовується лише для читання за замовчуванням. Простіше кажучи, колись призначений, змінна у функціональній мові не змінюється.
Авель

1
Так, я це знаю, і я фактично пишу код МЛ час від часу - саме тут я і надихнувся :) Це не про мову, якою ви користуєтесь, а про принципи та методи, якими ви користуєтесь. Із Haskell і doнотацією можна все впорядкувати :) Звичайно, Java не найкраща мова для написання у функціональному стилі, але, принаймні, це дозволяє вам писати надійний код - і це те , що мене дуже хвилює.
Андрій Андрей Листочкин
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.