EnumSet, особенности и внутреннее устройство
EnumSet — это специализированная реализация интерфейса Set в Java, предназначенная исключительно для работы с перечислениями (enum). Эта коллекция оптимизирована для хранения и обработки значений перечислений, обеспечивая высокую производительность и низкое потребление памяти. В отличие от других реализаций Set, таких как HashSet или LinkedHashSet, EnumSet обладает особыми свойствами, которые делают его идеальным выбором для работы с перечислениями.
Особенности EnumSet
Только для перечислений:
EnumSet работает исключительно с типами, основанными на enum. Если попытаться использовать его с любым другим типом, компилятор выбросит ошибку.
Компактное представление:
Внутреннее устройство EnumSet обеспечивает компактное хранение элементов, что делает его значительно более эффективным по сравнению с другими реализациями Set. Все элементы хранятся как биты в одном или нескольких словах (типично, long), что минимизирует использование памяти.
Порядок элементов:
EnumSet сохраняет порядок элементов в соответствии с их порядком в перечислении (enum). Этот порядок определяется положением значений в enum и никогда не изменяется.
Высокая производительность:
Операции добавления, удаления, и проверки наличия элемента выполняются очень быстро, так как они сводятся к операциям с битами.
Не синхронизирован:
Как и большинство коллекций в Java, EnumSet не является потокобезопасным. Для использования в многопоточной среде доступ к нему необходимо явно синхронизировать.
Внутреннее устройство EnumSet
Битовые маски:
Основной механизм, лежащий в основе EnumSet, это использование битовых масок для представления множеств значений перечисления. Каждому элементу перечисления сопоставляется определенный бит в числе. Это позволяет представлять множества элементов как набор битов.
Поддержка разных размеров перечислений:
Если количество элементов перечисления не превышает 64, EnumSet хранит все элементы в одном long. Если элементов больше, используется массив из нескольких long, чтобы вместить все возможные значения.
Типы реализаций EnumSet:
В зависимости от количества элементов в перечислении, EnumSet может использовать разные внутренние реализации:
RegularEnumSet: для небольших перечислений, где все значения могут храниться в одном long.
JumboEnumSet: для больших перечислений, где требуется использовать массив long для хранения всех значений.
Эти реализации скрыты от разработчика, так как выбор между ними осуществляется автоматически на основе размера перечисления.
Операции над множествами:
Благодаря битовому представлению, EnumSet поддерживает быстрые операции над множествами, такие как объединение, пересечение и разность. Эти операции выполняются за константное время O(1).
Сериализация:
EnumSet поддерживает сериализацию, при этом его внутреннее представление сохраняется и восстанавливается через стандартные механизмы сериализации Java.
Преимущества использования EnumSet
Производительность:
EnumSet значительно быстрее и эффективнее других реализаций Set, таких как HashSet, при работе с перечислениями. Операции добавления, удаления и проверки наличия элемента выполняются за константное время, что делает его идеальным для работы с множествами фиксированных значений.
Порядок элементов:
В отличие от HashSet, который не гарантирует порядок элементов, EnumSet сохраняет порядок, определенный в перечислении. Это упрощает работу с множествами, когда важен порядок элементов.
Экономия памяти:
Благодаря битовому представлению, EnumSet использует гораздо меньше памяти, чем другие реализации Set. Это особенно важно при работе с ограниченными ресурсами или в приложениях, где требуется высокая производительность.
Читабельность кода:
Использование EnumSet делает код более понятным и выразительным, так как он явно отражает работу с перечислениями и множествами значений.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-enumset
https://for-each.dev/lessons/b/-java-enumset
#Java #Training #Medium #EnumSet
EnumSet — это специализированная реализация интерфейса Set в Java, предназначенная исключительно для работы с перечислениями (enum). Эта коллекция оптимизирована для хранения и обработки значений перечислений, обеспечивая высокую производительность и низкое потребление памяти. В отличие от других реализаций Set, таких как HashSet или LinkedHashSet, EnumSet обладает особыми свойствами, которые делают его идеальным выбором для работы с перечислениями.
Особенности EnumSet
Только для перечислений:
EnumSet работает исключительно с типами, основанными на enum. Если попытаться использовать его с любым другим типом, компилятор выбросит ошибку.
Компактное представление:
Внутреннее устройство EnumSet обеспечивает компактное хранение элементов, что делает его значительно более эффективным по сравнению с другими реализациями Set. Все элементы хранятся как биты в одном или нескольких словах (типично, long), что минимизирует использование памяти.
Порядок элементов:
EnumSet сохраняет порядок элементов в соответствии с их порядком в перечислении (enum). Этот порядок определяется положением значений в enum и никогда не изменяется.
Высокая производительность:
Операции добавления, удаления, и проверки наличия элемента выполняются очень быстро, так как они сводятся к операциям с битами.
Не синхронизирован:
Как и большинство коллекций в Java, EnumSet не является потокобезопасным. Для использования в многопоточной среде доступ к нему необходимо явно синхронизировать.
Внутреннее устройство EnumSet
Битовые маски:
Основной механизм, лежащий в основе EnumSet, это использование битовых масок для представления множеств значений перечисления. Каждому элементу перечисления сопоставляется определенный бит в числе. Это позволяет представлять множества элементов как набор битов.
Поддержка разных размеров перечислений:
Если количество элементов перечисления не превышает 64, EnumSet хранит все элементы в одном long. Если элементов больше, используется массив из нескольких long, чтобы вместить все возможные значения.
Типы реализаций EnumSet:
В зависимости от количества элементов в перечислении, EnumSet может использовать разные внутренние реализации:
RegularEnumSet: для небольших перечислений, где все значения могут храниться в одном long.
JumboEnumSet: для больших перечислений, где требуется использовать массив long для хранения всех значений.
Эти реализации скрыты от разработчика, так как выбор между ними осуществляется автоматически на основе размера перечисления.
Операции над множествами:
Благодаря битовому представлению, EnumSet поддерживает быстрые операции над множествами, такие как объединение, пересечение и разность. Эти операции выполняются за константное время O(1).
Сериализация:
EnumSet поддерживает сериализацию, при этом его внутреннее представление сохраняется и восстанавливается через стандартные механизмы сериализации Java.
Преимущества использования EnumSet
Производительность:
EnumSet значительно быстрее и эффективнее других реализаций Set, таких как HashSet, при работе с перечислениями. Операции добавления, удаления и проверки наличия элемента выполняются за константное время, что делает его идеальным для работы с множествами фиксированных значений.
Порядок элементов:
В отличие от HashSet, который не гарантирует порядок элементов, EnumSet сохраняет порядок, определенный в перечислении. Это упрощает работу с множествами, когда важен порядок элементов.
Экономия памяти:
Благодаря битовому представлению, EnumSet использует гораздо меньше памяти, чем другие реализации Set. Это особенно важно при работе с ограниченными ресурсами или в приложениях, где требуется высокая производительность.
Читабельность кода:
Использование EnumSet делает код более понятным и выразительным, так как он явно отражает работу с перечислениями и множествами значений.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-enumset
https://for-each.dev/lessons/b/-java-enumset
#Java #Training #Medium #EnumSet
Baeldung
Guide to EnumSet | Baeldung
Quickly learn about the EnumSet and how to start using it in practical scenarios.
Основные методы EnumSet и их использование
of(E first, E... rest):
Создает EnumSet, содержащий указанные элементы перечисления.
allOf(Class<E> elementType):
Создает EnumSet, содержащее все элементы указанного перечисления.
noneOf(Class<E> elementType):
Создает пустой EnumSet для указанного типа перечисления.
range(E from, E to):
Создает EnumSet, содержащий элементы из указанного диапазона, включая границы.
complementOf(EnumSet<E> s):
Создает EnumSet, содержащее все элементы, отсутствующие в указанном EnumSet.
add(E e):
Добавляет указанный элемент в множество, если он еще отсутствует.
remove(Object o):
Удаляет указанный элемент из множества, если он присутствует.
contains(Object o):
Проверяет, присутствует ли указанный элемент в множестве.
isEmpty():
Проверяет, пусто ли множество.
size():
Возвращает количество элементов в множестве.
clear():
Удаляет все элементы из множества.
iterator():
Возвращает итератор для обхода элементов в множестве.
Примеры использования EnumSet
Управление набором флагов:
EnumSet идеально подходит для управления набором флагов. Допустим, у нас есть перечисление, представляющее разрешения пользователя:
Планировщик задач:
Допустим, у нас есть задача, которая должна выполняться в определенные дни недели:
Оптимизация кода:
Если ваш код часто работает с наборами элементов перечисления, использование EnumSet может значительно упростить и ускорить его. Например, при проверке множества состояний:
#Java #Training #Medium #EnumSet
of(E first, E... rest):
Создает EnumSet, содержащий указанные элементы перечисления.
EnumSet<Day> weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
Этот метод полезен, когда нужно создать множество с конкретными значениями перечисления. Порядок элементов в множестве соответствует их порядку в enum.
allOf(Class<E> elementType):
Создает EnumSet, содержащее все элементы указанного перечисления.
EnumSet<Day> allDays = EnumSet.allOf(Day.class);
Метод allOf полезен для создания множества, содержащего все возможные значения enum, что может быть полезно для инициализации настроек или параметров.
noneOf(Class<E> elementType):
Создает пустой EnumSet для указанного типа перечисления.
EnumSet<Day> noDays = EnumSet.noneOf(Day.class);
Этот метод используется, когда нужно создать пустое множество и добавлять элементы в него по мере необходимости.
range(E from, E to):
Создает EnumSet, содержащий элементы из указанного диапазона, включая границы.
EnumSet<Day> workdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
Этот метод позволяет легко создать множество с элементами, которые находятся между двумя значениями перечисления.
complementOf(EnumSet<E> s):
Создает EnumSet, содержащее все элементы, отсутствующие в указанном EnumSet.
EnumSet<Day> weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
EnumSet<Day> weekdays = EnumSet.complementOf(weekend);
Это полезно, когда нужно получить множество элементов, которые отсутствуют в другом множестве.
add(E e):
Добавляет указанный элемент в множество, если он еще отсутствует.
EnumSet<Day> days = EnumSet.noneOf(Day.class);
days.add(Day.MONDAY);
remove(Object o):
Удаляет указанный элемент из множества, если он присутствует.
days.remove(Day.MONDAY);
contains(Object o):
Проверяет, присутствует ли указанный элемент в множестве.
boolean isMondayIncluded = days.contains(Day.MONDAY);
isEmpty():
Проверяет, пусто ли множество.
boolean isEmpty = days.isEmpty();
size():
Возвращает количество элементов в множестве.
int size = days.size();
clear():
Удаляет все элементы из множества.
days.clear();
iterator():
Возвращает итератор для обхода элементов в множестве.
Iterator<Day> iterator = days.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
Примеры использования EnumSet
Управление набором флагов:
EnumSet идеально подходит для управления набором флагов. Допустим, у нас есть перечисление, представляющее разрешения пользователя:
enum Permission {
READ, WRITE, EXECUTE
}
EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class);
permissions.add(Permission.READ);
permissions.add(Permission.WRITE);
Теперь permissions содержит флаги READ и WRITE. Это очень удобно для управления разрешениями в приложениях.
Планировщик задач:
Допустим, у нас есть задача, которая должна выполняться в определенные дни недели:
EnumSet<Day> taskDays = EnumSet.of(Day.MONDAY, Day.WEDNESDAY, Day.FRIDAY);
for (Day day : taskDays) {
System.out.println("Task scheduled on: " + day);
}
Этот код выведет дни, в которые задача должна быть выполнена.
Оптимизация кода:
Если ваш код часто работает с наборами элементов перечисления, использование EnumSet может значительно упростить и ускорить его. Например, при проверке множества состояний:
enum State {
START, RUNNING, STOP, PAUSE
}
EnumSet<State> activeStates = EnumSet.of(State.RUNNING, State.PAUSE);
#Java #Training #Medium #EnumSet