Java for Beginner
675 subscribers
559 photos
156 videos
12 files
856 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
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 и их использование

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