Константи, перерахування (enum), і static import - и в java, stokito on software

Константа - це, грубо кажучи, змінна значення якої не змінюється під час роботи програми. Класичний приклад константи - число Пі (3,14 ...). Константи використовуються для боротьби з магічними числами. тобто незрозуміло що дають зрозуміти числами або рядками.

Але в замін є більш гнучкий модифікатор final:

У цьому прикладі була оголошена фінальна змінна з назвою PI і їй було відразу ж задано значення 3.14. Фінальним змінним значення можна задати тільки один раз і більше його можна міняти. Будь-яку спробу поміняти значення фінальної змінної (або поля) компілятор буде сприймати як помилку, тобто все так само як і з константами.

Різниця між фінальним змінної і константою в тому що ініціалізацію можна відкласти:

Така лінива ініціалізація наприклад часто використовується для створення незмінних об'єктів (англ. Immutable objects).

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

Статичне поле (модифікатор static) належить класу і для доступу до нього не потрібно створювати конкретний екземпляр об'єкта:

Зверніть увагу що в Яві, як і у всіх Сі подібних мовах, прийнято імена констант писати БОЛЬШІМІ_БУКВАМІ_РАЗДЕЛЯЯ_ІХ_ПОДЧЁРКІВАНІЕМ.

Тут варто ще зазначити що така константа може бути не просто числом, а повноцінним виразом, в якому теж можна звертатися до інших статичним полях або викликати статичні методи:

При цьому все обчислюється на етапі компіляції і не потрібно замінювати 60 * 60 * 24 на менш читається і очевидне вже обчислене вами 86400 (до того ж можливо неправильно розраховане).

Групування констант через перерахування

Дуже часто константи використовуються в декількох класах і їх хочеться їх все тримати в одному модулі. У Яві ООП примусове, тому все таки доведеться оголосити клас без методів і все константи помістити в нього. Наприклад клас констант для модифікаторів елементів мови Java:

У цьому прикладі легко помітити що його константи одного типу і їх обмежений список, тобто більше модифікаторів в Яві немає. Ось деякі з проблем цього класу:

  • Небезпечність типу (type unsafe): в методі, де потрібно передати значення перерахування, можна передати будь-яке число, а не тільки значення від 1 до 11;
  • Неінформативність: наприклад, при налагодженні значення 3 не скаже нам ні про що. А хотілося б побачити PRIVATE;
  • Схильність до помилок: наприклад, при додаванні нового елемента або при зміні послідовності існуючих. Наприклад годі й встежити, і у PUBLIC і PROTECTED поставити однакове значення 1. Тобто відсутній контроль з боку компілятора як за унікальністю значень констант, так і за можливістю випадкового привласнення змінним значень, які не відповідають жодній з цих констант.

Такі згруповані константи називаються перерахуваннями і в Java для них є спеціальна конструкція enum.

Перепишемо цей клас як перерахування:

І використовувати його можна як звичайну константу:

Зверніть увагу що перерахування не потрібно порівнювати через equals, досить просто порівняти за посиланням:

Взагалі тут потрібно відзначити що раніше, до п'ятої версії Java перерахувань не було, замість них доводилося використовувати класи зі статичними константами. Це я кажу до того, що багато класів з якими ви зіткнетеся залишилися написаними «дідівським» способом. Причому в стандартних класах їх не міняли, наприклад java.awt.Color.

Технічно перерахування представляють собою повноцінний клас який успадковується від java.lang.Enum. тобто запис public enum Modifier рівноцінна abstract class Modifier extends java.lang.Enum.

А якщо це клас, значить в нього можна додавати будь-яку кількість полів і методів:

При запуску цього прикладу в висновок буде надруковано public а не 1. У кожного enum'а зберігається поле name з його ім'ям (в нашому випадку PUBLIC). Ми переопределили (@Override) метод toString () всередині якого наводимо ім'я до нижнього регістру.

Це особливо зносить мозок тим хто раніше програмував в інших мовах програмування в яких перерахування є по суті згрупованими звичайними цілочисельними константами, тобто типами значення (містять безпосередньо значення, і при присвоєнні змінної одного типу значень іншому створюється копія присвоюється значення, на відміну від змінних посилального типу, при присвоєнні яких копіюються посилання на об'єкти, але не самі об'єкти).

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

Використання статичних імпорт

Перерахування природно підходять не для всіх випадків. Наприклад константа натурального логарифма e і константу π можна об'єднувати в перерахування. Давайте подивимося на клас містить цю константи:

Всі його поля public static final. Щоб кожен раз не писати ці модифікатори багато програмістів оголошують константи в інтерфейсі. тому що все його поля тепер вже public static final.

І ось кому то стрельнула думка: «А навіщо кожен раз писати повне ім'я інтерфейсу з константами, якщо можна його заімплементіть і отримати до них доступ безпосередньо?». І такі конструкції

перетворилися в такий кошмар

Конструкція статичного імпорту дозволяє отримати прямий доступ до статичних членам без необхідності успадкування від того типу, який містить ці статичні члени. Замість цього, програма імпортує члени індивідуально:

або все цілком:

Одного разу імпортований статичний член може бути використаний без вказівки імені класу:

Так коли ж слід використовувати статичний імпорт? Тільки в деяких випадках! Використовуйте його тільки, якщо інакше ви змушені оголошувати локальні копії констант або при неправильному використанні успадкування. Іншими словами, використання його виправдано, коли потрібне постійне використання статичних членів одного класу з одного або двох інших класів.

Імпорт всіх статичних методів з класу може бути частково шкідливо для читабельності; якщо ви потребуєте тільки в одному або двох методах, імпортуйте їх по-окремо. Використаний вміло, статичний імпорт може зробити вашу програму більш наочною, виключаючи з програмного коду нунжние повторення імен класів.

Як правильно оголосити константний клас?

Якщо все таки дуже треба, то оголошуйте константний клас як звичайний клас, а не інтерфейс. Тільки робіть його ще й фінальним (final), щоб від нього не можна було успадкувати. А ще було б непогано зробити його абстрактним (abstract), щоб можна було створити його екземпляр, адже все константи у нас статичні і ми звертаємося до полів класу а не об'єкта.

висновок

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

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

Схожі статті