Guia para EnumSet
1. Introdução
Neste tutorial, exploraremos a coleçãoEnumSet do pacotejava.util e discutiremos suas peculiaridades.
Mostraremos primeiro as principais características da coleção e, em seguida, passaremos pelos detalhes internos da aula para entender seus benefícios.
Finalmente, cobriremos as principais operações que ele fornece e implementaremos alguns exemplos básicos.
2. O que é umEnumSet
An EnumSet is a specialized Set collection to work with enum classes. Ele implementa a interfaceSet e se estende deAbstractSet:
EmboraAbstractSeteAbstractCollection forneçam implementações para quase todos os métodos das interfacesSeteCollection,EnumSet substitui a maioria deles.
Quando planejamos usar umEnumSet, temos que levar em consideração alguns pontos importantes:
-
It can contain only enum values e todos os valores devem pertencer ao mesmoenum
-
It doesn’t allow to add null values, jogando umNullPointerException na tentativa de fazer isso
-
It’s not thread-safe, então precisamos sincronizá-lo externamente, se necessário
-
Os elementos são armazenados seguindo a ordem em que são declarados noenum
-
It uses a fail-safe iterator que funciona em uma cópia, então não lançará umConcurrentModificationException se a coleção for modificada ao iterar sobre ela
3. Por que usarEnumSet
Como regra geral,EnumSet should always be preferred over any other Set implementation when we are storing enum values.
Nas próximas seções, veremos o que torna esta coleção melhor do que outras. Para isso, mostraremos brevemente os detalhes internos da aula para um melhor entendimento.
3.1. Detalhes da implementação
EnumSet é uma classepublicabstract que contém vários métodos de fábrica estáticos que nos permitem criar instâncias. O JDK fornece 2 implementações diferentes - sãopackage-privatee apoiadas por um vetor de bits:
-
RegularEnumSet e
-
JumboEnumSet
RegularEnumSet uses a single long to represent the bit vector. Cada bit do elementolong representa um valor deenum. O i-ésimo valor do enum será armazenado no i-ésimo bit, então é muito fácil saber se um valor está presente ou não. Since long is a 64-bit data type, this implementation can store up to 64 elements.
Por outro lado,JumboEnumSet uses an array of long elements as a bit vector.This lets this implementation store more than 64 elements. Funciona muito bem comoRegularEnumSet, mas fazendo alguns cálculos extras para encontrar o índice da matriz onde o valor está armazenado.
Sem surpresa, o primeiro elemento longo da matriz armazenará os 64 primeiros valores deenum, o segundo elemento nos próximos 64 e assim por diante.
Os métodos de fábricaEnumSet criam instâncias de uma implementação ou outra dependendo do número de elementos deenum:
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
Lembre-se de que ele leva em consideração apenas o tamanho da classeenum, não o número de elementos que serão armazenados na coleção.
3.2. Benefícios de usar umEnumSet
Devido à implementação de umEnumSet que descrevemos acima,all the methods in an EnumSet are implemented using arithmetic bitwise operations. Esses cálculos são muito rápidos e, portanto, todas as operações básicas são executadas em um tempo constante.
Se compararmosEnumSet com outras implementações deSet comoHashSet, a primeira é geralmente mais rápida porque os valores são armazenados em uma ordem previsível e apenas um bit precisa ser examinado para cada cálculo. Ao contrário deHashSet, não há necessidade de calcularhashcode para encontrar o intervalo certo.
Além disso, devido à natureza dos vetores de bits, umEnumSet é muito compacto e eficiente. Portanto, ele usa menos memória, com todos os benefícios que traz.
4. Operações Principais
A maioria dos métodos de umEnumSet funciona como qualquer outroSet, com exceção dos métodos para criar instâncias.
Nas próximas seções, mostraremos em detalhes todos os métodos de criação e cobriremos brevemente o restante dos métodos.
Em nossos exemplos, trabalharemos com umColorenum:
public enum Color {
RED, YELLOW, GREEN, BLUE, BLACK, WHITE
}
4.1. Métodos Criacionais
The most simple methods to create an EnumSet are allOf() and noneOf(). Desta forma, podemos criar facilmente umEnumSet contendo todos os elementos de nosso enumColor:
EnumSet.allOf(Color.class);
Da mesma forma, podemos usarnoneOf() para fazer o oposto e criar uma coleção vazia deColor:
EnumSet.noneOf(Color.class);
If we want to create an EnumSet with a subset of the enum elements we can use the overloaded of() methods. É importante diferenciar entre os métodos com um número fixo de parâmetros até 5 diferentes e aquele que usavarargs:
O Javadoc afirma que o desempenho da versãovarargs pode ser mais lento do que as outras devido à criação do array. Portanto, devemos usá-lo apenas se precisarmos adicionar inicialmente mais de 5 elementos.
Outra maneira de criar um subconjunto deenum é usando o métodorange():
EnumSet.range(Color.YELLOW, Color.BLUE);
No exemplo acima, oEnumSet contém todos os elementos deYellow aBlue. Eles seguem a ordem definida emenum:
[YELLOW, GREEN, BLUE]
Observe que ele inclui o primeiro e o último elementos especificados.
Another useful factory method is the complementOf() that allows us to exclude the elements passed as parameters. Vamos criar umEnumSet com todos os elementosColor, exceto preto e branco:
EnumSet.complementOf(EnumSet.of(Color.BLACK, Color.WHITE));
Se imprimirmos essa coleção, podemos ver que ela contém todos os outros elementos:
[RED, YELLOW, GREEN, BLUE]
Finalmente,we can create an EnumSet by copying all the elements from another EnumSet:
EnumSet.copyOf(EnumSet.of(Color.BLACK, Color.WHITE));
Internamente, ele chama o métodoclone.
Além disso,we can also copy all the elements from any Collection that contains enum elements. Vamos usá-lo para copiar todos os elementos de uma lista:
List colorsList = new ArrayList<>();
colorsList.add(Color.RED);
EnumSet listCopy = EnumSet.copyOf(colorsList);
Neste caso,listCopy contém apenas a cor vermelha.
4.2. Outras Operações
O restante das operações funcionam exatamente da mesma maneira que qualquer outra implementaçãoSet e não há diferença em como usá-las.
Portanto, podemos criar facilmente umEnumSet vazio e adicionar alguns elementos:
EnumSet set = EnumSet.noneOf(Color.class);
set.add(Color.RED);
set.add(Color.YELLOW)
Verifique se a coleção contém um elemento específico:
set.contains(Color.RED);
Iterar sobre os elementos:
set.forEach(System.out::println);
Ou simplesmente remova os elementos:
set.remove(Color.RED);
Isso, é claro, entre todas as outras operações que aSet suporta.
5. Conclusão
Neste artigo, mostramos os principais recursos deEnumSet, sua implementação interna e como podemos nos beneficiar de usá-lo.
Também cobrimos os principais métodos que ele oferece e implementamos alguns exemplos para mostrar como podemos usá-los.
Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.