Перечисления (enums)

enum — это вид класса. У него есть ограниченный набор элементов и все они доступны статически.

public enum HairColour {
    BLONDE, FAIR, RED, BROWN, BLACK
}

Если объявить метод, скажем, findPersonWith(HairColour colour), то все значения, которые можно будет передать в метод, — это BLONDE, FAIR, RED, BROWN, BLACK и null.

Person found = findPersonWith(HairColour.RED);

Перечисления пришли на смену целочисленным константам. Например, здесь проще совершить ошибку:

public static final COLOUR_BLONDE = 0;
public static final COLOUR_FAIR = 1;
public static final COLOUR_RED = 2;
public static final COLOUR_BROWN = 3;
public static final COLOUR_BLACK = 4;
Person found0 = findPersonWithHairColour(COLOUR_FAIR); // скомпилируется
Person found1 = findPersonWithHairColour(42); // увы, скомпилируется!

Стандартные методы enum'ов

Все перечисления являются наследниками класса Enum и обладают следующими instance-методами:

HairColour.BLACK.name(); // == "BLACK"
HairColour.BLACK.ordinal(); // == 4

И статическими методами:

HairColor.valueOf("RED"); // == HairColour.RED
HairColour.values(); // == { BLONDE, FAIR, RED, BROWN, BLACK }

Ordinal — порядковый номер. Он легко может измениться, если обменять значения местами, например, вместо BLONDE, FAIR, RED сделать RED, BLONDE, FAIR, то BLONDE.ordinal() изменится с 0 на 1, FAIR.ordinal() — с 1 на 2, а RED.ordinal() — с 2 на 0.

Стоит учитывать, что, т. к. в Java массивы изменяемы, метод values() каждый раз возвращает новую копию массива. Подробнее об экономии памяти в этой ситуации — в стате «Enum в Java. Маленькая недоработка».

Добавление собственных методов

Очень часто нужно добавить какую-нибудь информацию к элементам enum'а. Это можно сделать так:

public enum HairColour {
    // Пусть у каждого цвета волос
    // будет степень яркости.
    BLONDE(1),
    FAIR(.8f),
    RED(.7f),
    BROWN(.4f),
    BLACK(0);

    // Поле для хранения данных.
    // Должно быть финальным:
    // недопустимо, чтобы у элемента перечисления
    // было состояние.
    private final float brightness;

    // Конструктор. Он по умолчанию приватный,
    // изменить это нельзя.
    HairColour(float brightness) {
        this.brightness = brightness;
    }

    // геттер для поля
    public float getBrightness() {
        return brightness;
    }
    
    // Метод для поиска цвета
    // по уровню яркости.
    public static HairColour withBrightness(float brightness) {
        // обходим все возможные значения
        for (HairColour colour : values()) {
            
            // если у очередного цвета
            // подходящий уровень яркости — возвращаем
            if (colour.brightness == brightness) {
                return colour;
            }
        }
        
        // если нужный цвет не найден —
        // выбрасываем исключение
        throw new NoSuchElementException(
                "There's no HairColour with brightness " + brightness);
    }
}

В этом примере HairColour.RED.getBrightness() == .7f, HairColour.withBrightness(0) == HairColour.BLACK, а HairColour.withBrightness(.003f) бросит исключение NoSuchElementException.

Enum'ы могут реализовывать интерфейсы.

public enum HairColour implements Runnable {

    // без изменений

    @Override
    public void run() {
        System.out.println("person with " + name().toLowerCase() + " hair runs");
    }
}

HairColour.FAIR.run() выведет person with fair hair runs.

Собственные методы элементов enum'а

Отдельные элементы перечисления могут иметь свои методы. Например:

public enum HairColour implements Runnable {

    BLONDE(1),
    FAIR(.8f),
    RED(.7f) {
        @Override
        public boolean hasSoul() {
            return false;
        }
    },
    BROWN(.4f),
    BLACK(0);

    // без изменений
    
    public boolean hasSoul() {
        return true;
    }
}
Комментарии к уроку

Сообщить об ошибке