JavaRush /Java блог /Java Developer /Enum в Java: як використовувати клас
Автор
Milan Vucic
Репетитор по программированию в Codementor.io

Enum в Java: як використовувати клас

Стаття з групи Java Developer
Привіт! У цій статті я розповім вам про Java Enums. Уяви, що тобі поставили завдання: створити клас, який реалізує дні тижня. На перший погляд, нічого складного в цьому немає, і твій код матиме приблизно такий вигляд:

public class DayOfWeek {

   private String title;

   public DayOfWeek(String title) {
       this.title = title;
   }

   public static void main(String[] args) {
       DayOfWeek dayOfWeek = new DayOfWeek("Субота");
       System.out.println(dayOfWeek);
   }

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\''' +
               '}';
   }
}
І начебто все добре, але є одна проблема: у конструктор класу DayOfWeek можна передати будь-який текст. Таким чином хтось зможе створити день тижня "Жаба", "Хмарка" або "azaza322". Це явно не та поведінка, яку ми очікуємо, адже реальних днів тижня існує лише 7, і в кожного з них є назва. Тому наше завдання – якось обмежити коло можливих значень для класу "день тижня". До появи Java 1.5 розробники були змушені самостійно вигадувати рішення цієї проблеми, оскільки готового рішення в самій мові не існувало. У ті часи, якщо ситуація вимагала обмеженої кількості значень, робили так:

public class DayOfWeek {

   private String title;

   private DayOfWeek(String title) {
       this.title = title;
   }

   public static DayOfWeek SUNDAY = new DayOfWeek("Неділя");
   public static DayOfWeek MONDAY = new DayOfWeek("Понеділок");
   public static DayOfWeek TUESDAY = new DayOfWeek("Вівторок");
   public static DayOfWeek WEDNESDAY = new DayOfWeek("Середа");
   public static DayOfWeek THURSDAY = new DayOfWeek("Четвер");
   public static DayOfWeek FRIDAY = new DayOfWeek("П'ятниця");
   public static DayOfWeek SATURDAY = new DayOfWeek("Субота");

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\''' +
               '}';
   }
}
На що тут варто звернути увагу:
  • Приватний конструктор. Якщо конструктор позначений модифікатором private, об'єкт класу не можна створити за допомогою цього конструктора. А оскільки в цьому класі конструктор лише один, об'єкт DayOfWeek не можна створити взагалі.

    
    	public class Main {
    
       		public static void main(String[] args) {
          
           			DayOfWeek sunday = new DayOfWeek();//помилка!
       		}
    }
    
  • Водночас в класі містилася потрібна кількість public static об'єктів, які були ініціалізовані потрібним нам чином (назви днів правильні).

    Це давало змогу використовувати об'єкти в інших класах.

    
    	public class Man {
    
       		public static void main(String[] args) {
    
           			DayOfWeek sunday = DayOfWeek.SUNDAY;
    
           			System.out.println(sunday);
      		 }
    }
    

    Виведення:

    DayOfWeek{title='Неділя'}

Такий підхід багато в чому давав змогу вирішити завдання. У нашому розпорядженні були 7 днів тижня, і водночас ніхто не міг створити нові. Це рішення запропонував Джошуа Блох у книзі «Effective Java». Книга, до речі, дуже крута і обов'язкова до прочитання будь-якому Java-розробнику. З виходом Java 1.5 у мові з'явилося готове рішення для таких ситуацій – перелік Enum. Enum – теж клас. Але він спеціально "заточений" на вирішення завдань, схожих на наше: створення деякого обмеженого кола значень. Оскільки у творців Java вже були готові приклади (скажімо, мова С, у якій Enum уже існував), вони змогли створити оптимальний варіант.

Що таке enum?

Отже, що ж із себе представляє Enum у Java? Давай подивимося на прикладі того ж DayOfWeek:

public enum DayOfWeek {

   SUNDAY,
   MONDAY,
   TUESDAY,
   WEDNESDAY,
   THURSDAY,
   FRIDAY,
   SATURDAY
}
Виглядає вже набагато простіше :) Усередині нашого Enum знаходяться 7 констант зі статичним доступом. Ми вже можемо його використовувати для реалізації логіки в програмі. Наприклад, напишемо програму, яка визначатиме, чи потрібно школяреві сьогодні йти на навчання. У нашого школяра буде свій режим дня, позначений класом ScholarSchedule:

public class ScholarSchedule {

   private DayOfWeek dayOfWeek;
   //...інші поля


   public DayOfWeek getDayOfWeek() {
       return dayOfWeek;
   }

   public void setDayOfWeek(DayOfWeek dayOfWeek) {
       this.dayOfWeek = dayOfWeek;
   }
}
Змінна dayOfWeek у режимі дня визначає, який сьогодні день. А ось клас нашого школяра:

public class Scholar {

   private ScholarSchedule schedule;
   private boolean goToSchool;

   public void wakeUp() {
      
       if (this.schedule.getDayOfWeek() == DayOfWeek.SUNDAY) {
           System.out.println("Ура, можна поспати ще!");
       } else {
           System.out.println("Блін, знову до школи:(");
       }
   }
}
У методі wakeUp() за допомогою Enum визначаємо подальші дії школяра. Ми навіть не описували докладно, що означає кожна змінна в DayOfWeek, та це й не потрібно: механізм днів тижня і так очевидний, і якщо ми будемо його використовувати в поточному вигляді, будь-якому розробнику буде зрозуміло, що відбувається у твоєму коді. Ще один приклад зручності Enum: його константи можна використовувати з оператором switch. Наприклад, ми пишемо програму для суворої дієти, в якій страви розписані по днях:

public class VeryStrictDiet {
   public void takeLunch(DayOfWeek dayOfWeek) {
       switch (dayOfWeek) {
           case SUNDAY:
               System.out.println("Недільний обід! Сьогодні можна навіть трохи солодкого");
               break;
           case MONDAY:
               System.out.println("Обід для понеділка: куряча локшина!");
               break;
           case TUESDAY:
               System.out.println("Вівторок, сьогодні суп із селери :(");
               break;
               //...і так далі до кінця
       }
   }
}
Це одна з переваг Enum перед старим рішенням, яке застосовувалося до Java 1.5: старе рішення не можна було використовувати з switch.

Що ще потрібно знати про Enum?

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

public enum DayOfWeek {
  
   SUNDAY ("Неділя"),
   MONDAY ("Понеділок"),
   TUESDAY ("Вівторок"),
   WEDNESDAY ("Середа"),
   THURSDAY ("Четвер"),
   FRIDAY ("П'ятниця"),
   SATURDAY ("Субота");

   private String title;

   DayOfWeek(String title) {
       this.title = title;
   }

   public String getTitle() {
       return title;
   }

   @Override
   public String toString() {
       return "DayOfWeek{" +
               "title='" + title + '\''' +
               '}';
   }
}
Тепер у констант нашого Enum є поле title, геттер і перевизначений метод toString. Порівняно зі звичайними класами, на Enum наклали одне серйозне обмеження – від нього неможливо успадковуватися. Крім того, у перерахувань є характерні тільки для них методи:
  • values(): повертає масив з усіх значень, що зберігаються в Enum:

    
    public static void main(String[] args) {
       		System.out.println(Arrays.toString(DayOfWeek.values()));
    }
    

    Виведення:

    [DayOfWeek{title='Неділя'}, DayOfWeek{title='Понеділок'}, DayOfWeek{title='Вівторок'}, DayOfWeek{title=''Середа'}, DayOfWeek{title='Четвер'}, DayOfWeek{title='П'ятниця'}, DayOfWeek{title='Субота'}]

  • ordinal(): повертає порядковий номер константи. Відлік починається з нуля:

    
    	public static void main(String[] args) {
    
       		int sundayIndex = DayOfWeek.SUNDAY.ordinal();
       		System.out.println(sundayIndex);
    }
    

    Виведення:

    0
  • valueOf(): повертає об'єкт Enum, що відповідає переданому імені:

    
    public static void main(String[] args) {
       DayOfWeek sunday = DayOfWeek.valueOf("SUNDAY");
       System.out.println(sunday);
    }
    

    Виведення:

    DayOfWeek{title='Неділя'}
Зверни увагу: ми вказуємо назви елементів Enum великими літерами, оскільки це константи, а для них передбачено саме такий запис, а не camelCase.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ