0Pricing
Java Academy · Урок

EnumSet

Быстрые операции над множествами перечислений

«EnumSet» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.

Что такое EnumSet

EnumSet — специализированная реализация Set только для типов перечислений.

Внутри он представляет собой битовый вектор: каждой константе соответствует один бит. Поэтому он намного быстрее и экономичнее по памяти, чем HashSet с перечислениями.

import java.util.EnumSet;
import java.util.Set;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        Set<Day> weekend = EnumSet.of(Day.SAT, Day.SUN);
        System.out.println(weekend);
    }
}

Создание с помощью of

Фабричный метод EnumSet.of(...) создаёт множество из перечисленных констант. Существуют варианты для одного–пяти элементов, а также версия с переменным числом аргументов.

import java.util.EnumSet;

public class Main {
    enum Perm { READ, WRITE, EXECUTE }
    public static void main(String[] args) {
        EnumSet<Perm> perms = EnumSet.of(Perm.READ, Perm.WRITE);
        System.out.println(perms);
    }
}

allOf и noneOf

Есть ещё две фабрики:

  • allOf(Type.class) создаёт множество, содержащее все константы.
  • noneOf(Type.class) создаёт пустое множество, готовое для заполнения.
import java.util.EnumSet;

public class Main {
    enum Color { RED, GREEN, BLUE }
    public static void main(String[] args) {
        EnumSet<Color> all = EnumSet.allOf(Color.class);
        EnumSet<Color> none = EnumSet.noneOf(Color.class);
        none.add(Color.RED);
        System.out.println("all: " + all);
        System.out.println("built: " + none);
    }
}

range для последовательных констант

EnumSet.range(from, to) включает все константы между двумя границами, включая сами границы, в порядке объявления.

import java.util.EnumSet;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        EnumSet<Day> workdays = EnumSet.range(Day.MON, Day.FRI);
        System.out.println(workdays);
    }
}

complementOf

EnumSet.complementOf(set) возвращает множество всех констант, не входящих в заданное множество.

Это быстрый способ инвертировать выбор.

import java.util.EnumSet;

public class Main {
    enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
    public static void main(String[] args) {
        EnumSet<Day> work = EnumSet.range(Day.MON, Day.FRI);
        EnumSet<Day> rest = EnumSet.complementOf(work);
        System.out.println(rest);
    }
}

Операции над множествами

Поскольку EnumSet — полноценная реализация Set, Вы получаете объединение, пересечение и разность с помощью addAll, retainAll и removeAll.

Внутри эти операции выполняются с такой же скоростью, как побитовые операции.

import java.util.EnumSet;

public class Main {
    enum Tag { A, B, C, D }
    public static void main(String[] args) {
        EnumSet<Tag> x = EnumSet.of(Tag.A, Tag.B, Tag.C);
        EnumSet<Tag> y = EnumSet.of(Tag.B, Tag.C, Tag.D);
        EnumSet<Tag> inter = EnumSet.copyOf(x);
        inter.retainAll(y);
        System.out.println("intersection: " + inter);
    }
}

Проверка принадлежности

contains выполняет всего одну проверку бита, поэтому работает за постоянное время и очень быстро.

import java.util.EnumSet;

public class Main {
    enum Feature { DARK_MODE, BETA, ANALYTICS }
    public static void main(String[] args) {
        EnumSet<Feature> enabled = EnumSet.of(Feature.DARK_MODE, Feature.BETA);
        System.out.println(enabled.contains(Feature.BETA));
        System.out.println(enabled.contains(Feature.ANALYTICS));
    }
}

EnumSet вместо флагов

До появления EnumSet программисты использовали целочисленные битовые флаги, например READ | WRITE. EnumSet заменяет их, обеспечивая типобезопасность и читаемость.

Вы получаете производительность битовых полей без подверженного ошибкам ручного маскирования.

import java.util.EnumSet;
import java.util.Set;

public class Main {
    enum Style { BOLD, ITALIC, UNDERLINE }
    static void render(Set<Style> styles) {
        System.out.println("Applying: " + styles);
    }
    public static void main(String[] args) {
        render(EnumSet.of(Style.BOLD, Style.UNDERLINE));
    }
}

Перебор в порядке объявления

EnumSet выполняет перебор в естественном порядке констант, то есть в порядке их объявления.

В отличие от HashSet это обеспечивает предсказуемый и стабильный порядок перебора.

import java.util.EnumSet;

public class Main {
    enum Phase { ALPHA, BETA, RC, GA }
    public static void main(String[] args) {
        EnumSet<Phase> set = EnumSet.of(Phase.GA, Phase.ALPHA, Phase.RC);
        for (Phase p : set) System.out.println(p);
    }
}

Защитные копии с помощью copyOf

EnumSet.copyOf(collection) создаёт EnumSet из любой коллекции значений перечисления. Используйте его для создания безопасной копии или преобразования List.

import java.util.EnumSet;
import java.util.List;

public class Main {
    enum Role { ADMIN, EDITOR, VIEWER }
    public static void main(String[] args) {
        List<Role> source = List.of(Role.EDITOR, Role.VIEWER);
        EnumSet<Role> roles = EnumSet.copyOf(source);
        System.out.println(roles);
    }
}

Почему это быстро

Для перечислений, содержащих не более 64 констант, EnumSet использует один long в качестве битового вектора. Каждая операция выполняется за одну-две машинные инструкции.

Для множеств перечислений всегда предпочитайте EnumSet конструкции HashSet<MyEnum>.

import java.util.EnumSet;

public class Main {
    enum Bit { B0, B1, B2, B3 }
    public static void main(String[] args) {
        EnumSet<Bit> s = EnumSet.of(Bit.B0, Bit.B2);
        // contains is a single bit-and under the hood
        System.out.println(s.contains(Bit.B2));
    }
}

Быстрая проверка

Проверьте свои знания об EnumSet.

Итоги

Вы изучили EnumSet:

  • Битовый Set для перечислений — очень быстрый и компактный.
  • Фабрики: of, allOf, noneOf, range, complementOf, copyOf.
  • Перебор выполняется в порядке объявления.
  • Это типобезопасная замена целочисленным битовым флагам.

Далее — соответствующий тип карты: EnumMap.

import java.util.EnumSet;

public class Main {
    enum X { A, B }
    public static void main(String[] args) {
        System.out.println("EnumSet recap: " + EnumSet.allOf(X.class));
    }
}

Часто задаваемые вопросы

Урок «EnumSet» бесплатный?

Да — полный текст урока «EnumSet» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.

Чему я научусь в уроке «EnumSet»?

Быстрые операции над множествами перечислений Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Java Academy?

Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «EnumSet»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Java Academy?

Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Перечисления с полями и методами
  2. Абстрактные методы в перечислениях
  3. EnumSet
  4. EnumMap
← Назад к Java Academy