Що таке перерахунки і чому вони корисні?


488

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

Я ніколи не використовував enum s і вже більше двох років програмую на Java. І, мабуть, вони сильно змінилися. Тепер вони навіть отримують повну підтримку ООП всередині себе.

Тепер чому і для чого я повинен використовувати enum у щоденному програмуванні?



можливий дублікат Enum на Java. Переваги?
finnw

Ви не можете інстанціювати enums, оскільки він має приватний конструктор, вони інстанціюються під час запуску jvm, тому його одиночний, Enums не є безпечним для потоків.
Арнав Джоші

Відповіді:


633

Ви завжди повинні використовувати enums, коли змінна (особливо параметр методу) може взяти лише одне з невеликого набору можливих значень. Прикладами можуть бути такі речі, як константи типу (статус контракту: "постійний", "темп", "учень") або прапори ("виконувати зараз", "відкласти виконання").

Якщо ви використовуєте enums замість цілих чисел (або String-кодів), ви збільшуєте перевірку часу компіляції і уникаєте помилок при передачі недійсних констант, і ви документуєте, які значення є законними для використання.

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

Як приклад, що краще?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

проти

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

Виклик методу, як:

int sweetFoobangCount = countFoobangs(3);

потім стає:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

У другому прикладі відразу зрозуміло, які типи дозволені, документи та реалізація не можуть вийти з синхронізації, і компілятор може це застосувати. Також недійсний дзвінок на кшталт

int sweetFoobangCount = countFoobangs(99);

більше не можливо.


41
Якщо ви використовуєте enums та хочете дозволити комбінацію значень, використовуйте EnumSet. Це стосується всіх видів акуратних помічників, таких як загальнодоступний статичний фінал EnumSet <FB_TYPE> ALL = EnumSet.allOf (FB_TYPE.class);
RobAu

20
Ці відповіді - це ті, кого я дуже люблю бачити в ТА, тому що хтось доклав до цього реальних зусиль, хороша робота, я розумію, перераховує зараз!
Поділений

1
Я не думаю, що це правда you should *always* use enums when a variable can only take one out of a small set of possible values. Використання постійних значень як "двійкового прапора" (з логічним orінжином) може бути корисним для програм у режимі реального часу, де вам не вистачає пам'яті.
Еліст

@Elist, використовуючи enums, збільшує читабельність ваших кодів. Якщо ви використовуєте константи протягом певної частини часу, ви або ваш наступник не знаєте, для чого вони використовуються ...
:)

136

Навіщо використовувати будь-яку функцію мови програмування? Причина, з якої ми взагалі володіємо мовами, - це

  1. Програмісти для ефективного та правильного вираження алгоритмів у формі можуть використовувати комп’ютери.
  2. Обслуговуючі, щоб зрозуміти алгоритми, які інші написали та правильно внесли зміни.

Енуми покращують як вірогідність коректності, так і читабельності без написання багато табличок. Якщо ви готові написати котельну табличку, тоді ви можете "імітувати" перерахунки:

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Тепер ви можете написати:

Color trafficLightColor = Color.RED;

Котельна плита вище має такий же ефект, як і

public enum Color { RED, AMBER, GREEN };

Обидва надають однаковий рівень перевірки допомоги від компілятора. Котельня плита просто більше набирається. Але економія багато набравши тексту робить програміста більш ефективним (див. 1), тому це є вагомою функцією.

Варто також хоча б ще однієї причини:

Переключити заяви

Одне, що static finalсимуляція перерахувань вище не дає вам приємні switchвипадки. Для типів перерахунків Java-комутатор використовує тип своєї змінної, щоб вивести обсяг випадків перерахунків, тому для enum Colorвищезгаданого просто потрібно сказати:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Зауважте, це не Color.REDу випадках. Якщо ви не використовуєте enum, єдиним способом використання названих кількостей switchє щось на зразок:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

Але тепер змінна для зберігання кольору повинна мати тип int. Хороша компіляторська перевірка перерахунків таstatic final імітації вже немає. Не щасливий.

Компроміс полягає у використанні скалярного члена при моделюванні:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Зараз:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

Але зауважте, ще більше котельня!

Використання enum як синглтон

З котла вище можна зрозуміти, чому enum забезпечує спосіб реалізації одиночної форми. Замість написання:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

а потім отримати доступ до нього за допомогою

SingletonClass.INSTANCE

ми можемо просто сказати

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

що дає нам те саме. Ми можемо піти з цим , тому що Java перерахувань будуть реалізовані в вигляді повних класів тільки з невеликим синтаксичним цукром посипають зверху. Це знову менше шаблону, але це не очевидно, якщо ідіома вам не знайома. Мені також не подобається той факт, що ви отримуєте різні функції перерахування, хоча вони не мають великого сенсу для одиночного: ordі valuesт. Д. (Насправді є складніше моделювання, де Color extends Integerце буде працювати з комутатором, але воно настільки складне, що це ще більше чітко показує, чому enumкраща ідея.)

Безпека нитки

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

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

Якщо багато потоків дзвонить getInstanceодночасно, поки INSTANCEвоно все ще є нульовим, можна створити будь-яку кількість екземплярів. Це погано. Єдине рішення - додати synchronizedдоступ для захисту змінної INSTANCE.

Однак у static finalнаведеному вище коді цієї проблеми немає. Він створює екземпляр охоче під час завантаження класу. Завантаження класів синхронізовано.

enumОдноточечного ефективно лінива , тому що він ніколи не ініціалізується до першого використання. Ініціалізація Java також синхронізована, тому декілька потоків не можуть ініціалізувати більше ніж один екземпляр INSTANCE. Ви отримуєте ліниво ініціалізований синглтон з дуже маленьким кодом. Єдиний мінус - досить незрозумілий синтаксис. Вам потрібно знати ідіому або досконало зрозуміти, як працює завантаження та ініціалізація класів, щоб знати, що відбувається.


15
Цей останній абзац справді прояснив ситуацію, що склалася для мене. Дякую! Кожен читач, який скумує, повинен перечитати це.
Василь Бурк

Я читав це, stackoverflow.com/questions/16771373/… . Тепер я плутаю ваш останній пункт. Яким чином enum не надає функцію ініціалізації прокладки?
Deepankar Singh

static finalполя ініціалізуються в час ініціалізації класу , не завантажуючи час. Це точно так само, як і при enumпостійній ініціалізації (насправді вони однакові під кришкою). Ось чому намагання реалізувати «розумний» лінивий код ініціалізації для синглів завжди було безглуздим, навіть у першій версії Java.
Холгер

42

Окрім вже згаданих випадків використання, я часто знаходжу переліки корисними для реалізації стратегії, дотримуючись деяких основних вказівок щодо ООП:

  1. Маючи код, де є дані (тобто всередині самої enum - або часто в межах констант enum, які можуть переосмислювати методи).
  2. Реалізація інтерфейсу (або більше) для того, щоб не прив’язувати клієнтський код до enum (який повинен містити лише набір реалізацій за замовчуванням).

Найпростішим прикладом може бути набір Comparatorреалізацій:

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

Цей "шаблон" може бути використаний у набагато складніших сценаріях, широко використовуючи всі вигоди, які поставляються із перерахунком: повторення примірників, покладання на їх неявний порядок, отримання екземпляра за його ім'ям, статичні методи, що забезпечують потрібний екземпляр для конкретних контекстів і т. д. І все ж у вас все це приховано за інтерфейсом, тому ваш код буде працювати з користувацькими реалізаціями без змін, якщо ви хочете щось, що недоступне серед "параметрів за замовчуванням".

Я бачив, що це успішно застосовується для моделювання поняття про деталізацію часу (щоденне, щотижневе тощо), де вся логіка була інкапсульована в enum (вибираючи правильну деталізацію для заданого періоду часу, специфічну поведінку, пов'язану з кожною зернистістю як постійну методи тощо). І все-таки, Granularityяк бачив сервісний рівень, був просто інтерфейс.


2
Ви також можете додати CASE_INSENSITIVE { @Override public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); }. Однією з переваг, про яку ще не було сказано, є те, що ви отримуєте надійну підтримку серіалізації; стійка форма містить лише ім'я класу та ім’я постійної особи, не залежно від деталей реалізації ваших компараторів.
Холгер

32

Щось, що ніхто з інших відповідей не охопив, що робить перерахунки особливо потужними, - це можливість мати шаблонні методи . Методи можуть бути частиною базового перерахунку та переосмисленими для кожного типу. І, маючи поведінку, пов’язану з перерахуванням, вона часто усуває необхідність побудови if-else чи перемикання висловлювань, як це демонструє ця публікація в блозі - де enum.method()відбувається те, що спочатку було б виконано всередині умовного. Цей же приклад також показує використання статичного імпорту з перерахунками, а також створює набагато більш чистий DSL код.

Деякі інші цікаві якості включають те, що переліки забезпечують реалізацію equals(), toString()а hashCode()також реалізацію Serializableта Comparable.

Для повного проходження всього, що може запропонувати переліжникам, я настійно рекомендую Брюс Еккель « Мислення на Java» 4-го видання, який присвячує цілу главу цій темі. Особливо висвітлюються приклади, що включають гру «Рок, папір», ножиці (тобто RoShamBo) в якості перерахованих.


23

З документів Java -

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

Поширений приклад - заміна класу набором приватних статичних кінцевих констант int (у межах розумної кількості констант) на enum-тип. В основному, якщо ви думаєте, що знаєте всі можливі значення "чогось" під час компіляції, ви можете представляти це як тип перерахунку. Енуми забезпечують читабельність та гнучкість для класу із константами.

Мало інших переваг, які я можу подумати про види перерахунків. Вони завжди є одним екземпляром певного класу перерахунків (звідси і концепція використання переліків як сінгтон). Ще одна перевага полягає в тому, що ви можете використовувати enums як тип у операторі switch-case. Також ви можете використовувати toString () на enum, щоб надрукувати їх як читабельні рядки.


8
Чи використовуєте ви перерахунок за всі 366 днів у році? Це фіксований набір констант (366) (дні не змінюються). Отже, це говорить про те, що вам слід. : - / Я обмежував би розмір фіксованого набору.
moinudin

2
@marcog Маючи трохи розумного мислення, можливо, можна узагальнити дні тижня та дні кожного місяця у невеликій кількості.
Джеймс П.

1
Якщо говорити про дні тижня… DayOfWeekenum тепер заздалегідь визначений, вбудований у Java 8 і пізніше як частина java.time фреймворку (і переноситься назад на Java 6 та 7 та Android ).
Василь Бурк

19

Тепер чому і для чого я повинен використовувати enum у щоденному програмуванні?

Ви можете використовувати Enum для представлення невеликого фіксованого набору констант або режиму внутрішнього класу, збільшуючи при цьому читабельність. Також Enums може забезпечити певну жорсткість при використанні в параметрах методу. Вони пропонують цікаву можливість передачі інформації конструктору, як у прикладі Планет на сайті Oracle, і, як ви виявили, також дозволяють простий спосіб створити однотонний шаблон.

Наприклад: Locale.setDefault(Locale.US)читає краще Locale.setDefault(1)та застосовує використання фіксованого набору значень, показаного в IDE, коли ви додаєте .роздільник замість усіх цілих чисел.


@arnt Я також виправив граматику у питанні. Дякую.
Джеймс П.

13

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

Чому б не використовувати Stringабо intзамість них Enumконстант?

  1. Компілятор не дозволяє допускати помилки друку , а також значення з фіксованого набору, оскільки перерахунки є типами самі по собі. Наслідки:
    • Вам не доведеться писати попередню умову (або посібник if), щоб переконатися, що ваш аргумент знаходиться в допустимому діапазоні.
    • Інваріант типу приходить безкоштовно.
  2. Енуми можуть мати поведінку, як і будь-який інший клас.
  3. Напевно, вам знадобиться аналогічний об'єм пам'яті, щоб використовувати Strings, у будь-якому випадку (це залежить від складності Enum).

Більше того, кожен із Enumекземплярів російського класу - це клас, для якого можна визначити його індивідуальну поведінку.

Крім того, вони гарантують безпеку ниток при створенні екземплярів (коли enum завантажується), що побачило велике застосування у спрощенні Singleton Pattern .

Цей блог ілюструє деякі його програми, такі як Державна машина для розбору.


13

Корисно знати, що enumsподібно до інших класівConstant полями та a private constructor.

Наприклад,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

Компілятор складає його наступним чином;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}

12

enumозначає перерахування, тобто згадка (ряд речей) одна за одною.

Перерахування є тип даних , який містить фіксований набір констант.

АБО

An enum- це просто як class, з фіксованим набором екземплярів, відомих під час компіляції.

Наприклад:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Переваги перерахунку:

  • enum покращує безпеку типу під час перевірки під час компіляції, щоб уникнути помилок під час виконання.
  • enum може бути легко використаний в комутаторі
  • перерахунок можна пройти
  • enum може мати поля, конструктори та методи
  • enum може реалізовувати багато інтерфейсів, але не може поширювати жоден клас, оскільки він внутрішньо розширює клас Enum

для більше


9

Що таке перерахунок

  • enum - ключове слово, визначене для перерахування нового типу даних. Перерахування Typesafe слід застосовувати довільно. Зокрема, вони є надійною альтернативою простим String або int-константам, які використовуються в набагато більш старих API для представлення наборів пов'язаних елементів.

Навіщо використовувати enum

  • енюми неявно остаточні підкласи java.lang.Enum
  • якщо enum є членом класу, це неявно статично
  • new ніколи не можна використовувати із enum, навіть у самому типі enum
  • name і valueOf просто використовують текст констант enum, тоді як toString може бути відмінено для надання будь-якого вмісту, за бажанням
  • для констант перерахунків дорівнює і == - це одне і те ж, і їх можна використовувати взаємозамінно
  • константи перерахунків є загальноприйнятними статичними фіналами

Примітка

  • enums не може поширити жоден клас.
  • Перерахунок не може бути суперкласом.
  • порядок появи констант enum називається їх "природним порядком" і визначає порядок, що використовується і іншими елементами: CompareTo, порядок ітерації значень, EnumSet, EnumSet.range.
  • Перерахування може мати конструктори, статичні блоки та блоки примірників, змінні та методи, але не може мати абстрактних методів.

4
Ви не пояснюєте, навіщо використовувати переписки. Ви просто перелічите кілька властивостей переліків під незв'язаними заголовками.
Дункан Джонс

@DuncanJones не робить терміни остаточними, статичні задають мету використання перерахунків?
tinker_fairy

8

Крім усього сказаного іншими. У старшому проекті, над яким я працював, багато спілкування між сутностями (незалежними програмами) використовувало цілі числа, які представляли собою невеликий набір. Було корисно оголосити набір, як enumзі статичними методами, щоб отримати enumоб'єкт від valueта viceversa. Код виглядав більш чистим, зручність використання корпусу та легше писати в журнали.

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

Створіть enum об'єкт із отриманих значень (наприклад, 1,2) за допомогоюProtocolType.fromInt(2) Write в журнали, використовуючиmyEnumObj.name

Сподіваюсь, це допомагає.


6

Енум успадковує всі методи Objectкласу та абстрактного класуEnum . Таким чином, ви можете використовувати його методи для відображення, багатопотокової читання, серіалізації, порівнянні тощо. Якщо ви просто оголосите статичну константу замість Enum, ви не можете. Крім того, значення Enum також може передаватися шару DAO.

Ось приклад програми для демонстрації.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}

4

ENum означає "Перелічений тип". Це тип даних, що має фіксований набір констант, який ви самі визначаєте.


Ви не пояснили, для чого використовувати enum.
Дункан Джонс

4
Так. Ви використовуєте його для зберігання фіксованого набору констант, який ви самі визначаєте. Конкретне застосування цього питання залежить від вас. Не існує такого поняття, як сказати, коли, чому або як щось використовувати. Це залежить від потреб розробника. Все, що вам потрібно, щоб зрозуміти, що це таке і як це працює.
Стів

4

На мою думку, всі відповіді, які ви отримали до цього часу, є справедливими, але, на моєму досвіді, я би це висловив кількома словами:

Використовуйте enums, якщо ви хочете, щоб компілятор перевірив дійсність значення ідентифікатора.

В іншому випадку ви можете використовувати рядки, як завжди (напевно, ви визначили деякі "умови" для свого додатка), і ви будете дуже гнучкими ... але ви не отримаєте 100% захист від помилок на друках на своїх струнах, і ви зрозумієте їх лише під час виконання.


3

Використовуйте переліки для ТИПОВОЇ БЕЗПЕКИ, це мовна функція, тому ви зазвичай отримуєте:

  • Підтримка компілятора (негайно дивіться проблеми типу)
  • Підтримка інструментів в IDE (автоматичне доповнення у випадку перемикання, відсутні випадки, примусовий пристрій, ...)
  • У деяких випадках продуктивність enum також чудова ( EnumSet , типова альтернатива традиційним "бітовим прапорам" на основі int ).

Енуми можуть мати методи, конструктори, можна навіть використовувати enums всередині enums та комбінувати enums з інтерфейсами.

Розгляньте переліки як типи, щоб замінити чітко визначений набір констант int (які Java "успадкував" від C / C ++), а в деяких випадках замінити бітові прапори.

У книзі « Ефективна Java 2-е видання » є ціла глава про них і йдеться про більш детальну інформацію. Також дивіться цю публікацію про переповнення стека .


2

Java дозволяє обмежувати змінну лише одним із декількох заздалегідь заданих значень - іншими словами, одним значенням із переліченого списку. Використання enumsможе допомогти зменшити помилки у вашому коді. Ось приклад enumsпоза класу:

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

Це обмежує coffeesizeдо мати або: BIG, HUGEабо в OVERWHELMINGякості змінної.


2

Енум? Навіщо його використовувати? Я думаю, це більш зрозуміло, коли ти будеш ним користуватися. Я маю той самий досвід.

Скажімо, у вас є робота зі створення, видалення, редагування та читання бази даних.

Тепер, якщо ви створюєте enum як операцію:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Тепер ви можете заявити щось на кшталт:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

Так ви можете використовувати його багатьма способами. Завжди добре мати перерахунок на конкретні речі, оскільки операцією з базою даних у наведеному вище прикладі можна керувати, перевіряючи поточну операцію . Можливо, можна сказати, що це може бути досягнуто і зі змінними та цілими значеннями. Але я вважаю, що Енум - більш безпечний і програміст.

Інша річ: я думаю, що кожен програміст любить булеві , чи не так? Оскільки він може зберігати лише два значення, два конкретні значення. Таким чином, Enum можна вважати таким, що має один і той же тип засобів, де користувач визначатиме, скільки і який тип цінностей він буде зберігати, лише дещо по-іншому. :)


1

Поки мені ніколи не потрібно було користуватися переписками. Я читав про них з тих пір, як вони були представлені в тиграх 1.5 або версії, як її називали ще в той день. Вони ніколи не вирішували «проблеми» для мене. Для тих, хто цим користується (і я бачу, що багато хто з них робить), я впевнений, що це безумовно служить певній меті. Просто мій 2 фунти.


1

Тут є багато відповідей, просто хочу вказати на два конкретні:

1) Використання в якості констант у Switch-caseзаяві. Корпус комутатора не дозволить використовувати об’єкти String для case. Енуми стають у нагоді. Детальніше: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/

2) Реалізація Singleton Design Pattern- Енум знову приходить на допомогу. Використання тут: Який найкращий підхід для використання Enum як сингтона на Java?


1

Що дало мені момент Ah-Ha, це таке усвідомлення: що Enum має приватний конструктор, доступний лише через публічне перерахування:

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}

1

Що стосується мене, щоб зробити код читабельним у майбутньому, то найкорисніший застосований випадок перерахування представлений у наступному фрагменті:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};

1

На моєму досвіді я бачив, що використання Enum іноді призводить до того, що системи дуже важко змінювати. Якщо ви використовуєте Enum для набору домену конкретних значень , які часто змінюється, і у нього є багато інших класів і компонентів , які залежать від нього, ви можете розглянути НЕ використовуючи Enum.

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

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

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


1

На основі перерахунку синглтон

сучасний погляд на стару проблему

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

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

Як це працює? Що ж, другий рядок коду може вважатися приблизно таким:

public final static Singleton SINGLETON = new Singleton(); 

І ми отримуємо добрий старий ранній ініціалізований синглтон.

Пам'ятайте, що оскільки це перерахунок, ви завжди можете отримати доступ до примірника Singleton.INSTANCEтакож:

Singleton s = Singleton.INSTANCE;
Переваги
  • Для запобігання створенню інших екземплярів синглтона під час десеріалізації використовуйте сингл на основі переліків, оскільки серіалізація перерахунку переймається JVM. Серіюлізація та десеріалізація Enum працюють інакше, ніж для звичайних об'єктів Java. Єдине, що серіалізується - це ім'я значення enum. Під час процесу десеріалізації перерахунокvalueOf метод використовується з десеріалізованим іменем, щоб отримати бажаний екземпляр.
  • Сінгл на основі Енума дозволяє захистити себе від атаки відбиття. Тип enum фактично розширює Enumклас java . Причиною того, що відображення не може бути використане для створення екземплярів об'єктів типу enum, є те, що специфікація java відключає, і це правило кодується при реалізації newInstanceметоду Constructorкласу, який зазвичай використовується для створення об'єктів за допомогою відображення:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Енум не повинен бути клонований, оскільки має бути рівно один екземпляр кожного значення.
  • Найбільш лаконічний код серед усіх одиночних реалізацій.
Недоліки
  • Сингл на основі перерахунків не дозволяє ледачої ініціалізації.
  • Якщо ви змінили дизайн і хотіли перетворити синглтон в мультитон, enum це не дозволить. Шаблон мультитона використовується для керованого створення декількох екземплярів, якими він управляє за допомогою a map. Замість того, щоб мати один екземпляр на додаток (наприклад, java.lang.Runtime), мультитонний шаблон натомість забезпечує один екземпляр на ключ .
  • Enum з'являється лише в Java 5, тому ви не можете використовувати його в попередній версії.

Існує кілька реалізацій однотонного малюнка, кожен з яких має переваги та недоліки.

  • Швидке завантаження синглів
  • Двічі перевірений блокування синглтон
  • Ідіомія власника ініціалізації на вимогу
  • На основі перерахунку синглтон

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


0

Я використовував би перерахунки як корисний інструмент відображення, уникаючи багаторазових за if-else умови впровадження деяких методів.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

Тож метод by(String label)дозволяє отримати перелічене значення ненумерованим. Крім того, можна придумувати відображення між двома перерахунками. Також можна спробувати "1 до багатьох" або "багато до багатьох" на додаток до відношення за замовчуванням "один до одного"

Зрештою, enumце клас Java. Таким чином, ви можете мати mainметод всередині нього, який може бути корисним, коли потрібно виконати кілька операцій з картографуванням argsвідразу.


0

Замість того, щоб робити купу декларацій const int

Ви можете згрупувати їх усіх в 1 перерахунку

Тож все це організоване загальною групою, до якої вони належать


0

Енуми - це як заняття. Як і клас, він також має методи та атрибути.

Відмінності від класу такі: 1. константи перерахунку є публічними, статичними, кінцевими. 2. Enum не може бути використаний для створення об'єкта, і він не може розширювати інші класи. Але він може реалізувати інтерфейси.


0

Окрім @BradB відповіді:

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

"Хо, зачекайте, це може виглядати як один і той же тип, правда? Зрештою, вони перерахунки з тим же ім'ям - і це не перерахунки просто цілі числа під капотом?" І з цих причин ваш компілятор, ймовірно, не позначить використання одного визначення самого типу там, де він очікував іншого. Але насправді вони (в більшості важливих способів) різного типу. Найголовніше, що вони мають різні області даних - значення, прийнятні для даного типу. Додавши значення, ми ефективно змінили тип enum і, таким чином, порушуємо зворотну сумісність.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.