Javanese Online

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

Иногда нужно описать ограниченное множество элементов. Встарь это делали посредством целочисленных констант:

public final class HairColourInt {

    // не позволим никому создавать экземпляры
    private HairColourInt() {}

    public static final int BLONDE = 0;
    public static final int FAIR = 1;
    public static final int RED = 2;
    public static final int BROWN = 3;
    public static final int BLACK = 4;

}

Минусов у такого подхода несколько:

Enum

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

Другие названия: enumerated type, перечисляемый тип, перечисление.

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

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

Person redhead = findPersonWith(HairColour.RED);

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

Все enum'ы являются наследниками класса java.lang.Enum и обладают следующими instance-методами:

name()
Имя константы. HairColour.BROWN.name() == "BROWN"
ordinal()
Порядковый номер. HairColor.BLONDE.ordinal() == 0

Также компилятор генерирует для каждого enum-класса следующие статические методы:

valueOf(String name)
Находит константу по имени. HairColour.valueOf("BROWN") == HairColour.BROWN; HairColour.valueOf("YELLOW") бросит IllegalArgumentException, т. к. константы с таким именем нет
values()
Массив допустимых значений. HairColor.values() == [BLONDE, FAIR, RED, BROWN, BLACK]

Стоит учитывать, что, т. к. в 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;
    }
}

Таким образом, enum — это не просто набор констант, это почти полноценный класс и очень мощный инструмент.

Комментарии к уроку

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

Javanese.Online в GitHub

Чаты и каналы в Telegram

RSS-лента