Comparação HashSet e TreeSet
1. Introdução
Neste artigo, vamos comparar duas das implementações Java mais populares da interfacejava.util.Set -HashSeteTreeSet.
2. Diferenças
HashSeteTreeSet são folhas do mesmo ramo, mas diferem em alguns assuntos importantes.
2.1. Encomenda
HashSet stores the objects in random order, whereas TreeSet applies the natural order of the elements. Vejamos o seguinte exemplo:
@Test
public void givenTreeSet_whenRetrievesObjects_thenNaturalOrder() {
Set set = new TreeSet<>();
set.add("example");
set.add("is");
set.add("Awesome");
assertEquals(3, set.size());
assertTrue(set.iterator().next().equals("Awesome"));
}
Depois de adicionar os objetosString emTreeSet, vemos que o primeiro é “Incrível”, embora tenha sido adicionado no final. Uma operação semelhante feita comHashSet não garante que a ordem dos elementos permanecerá constante ao longo do tempo.
2.2. ObjetosNull
Outra diferença é queHashSet can store null objects, while TreeSet does not allow them:
@Test(expected = NullPointerException.class)
public void givenTreeSet_whenAddNullObject_thenNullPointer() {
Set set = new TreeSet<>();
set.add("example");
set.add("is");
set.add(null);
}
@Test
public void givenHashSet_whenAddNullObject_thenOK() {
Set set = new HashSet<>();
set.add("example");
set.add("is");
set.add(null);
assertEquals(3, set.size());
}
Se tentarmos armazenar o objetonull em umTreeSet, a operação resultará em umNullPointerException lançado. A única exceção era em Java 7, quando era permitido ter exatamente um elementonull emTreeSet.
2.3. atuação
Simplificando,HashSet é mais rápido do queTreeSet.
HashSet fornece desempenho de tempo constante para a maioria das operações comoadd(),remove()econtains(), versus o tempolog (n) oferecido pelo TreeSet.
Normalmente, podemos ver quethe execution time for adding elements into TreeSet is much better than for the HashSet.
Lembre-se de que a JVM pode não estar aquecida, portanto os tempos de execução podem ser diferentes. Uma boa discussão sobre como projetar e executar microtestes usando várias implementações deSet está disponívelhere.
2.4. Métodos Implementados
TreeSet is rich in functionalities, implementando métodos adicionais como:
-
pollFirst() - para retornar o primeiro elemento, ounull seSet estiver vazio
-
pollLast() - para recuperar e remover o último elemento ou retornarnull seSet estiver vazio
-
first() - para devolver o primeiro item
-
last() – para devolver o último item
-
ceiling() - para retornar o menor elemento maior ou igual ao elemento dado, ounull se não houver tal elemento
-
lower() - para retornar o maior elemento estritamente menor do que o elemento dado, ounull se não houver tal elemento
Os métodos mencionados acima tornamTreeSet muito mais fácil de usar e mais poderoso do queHashSet.
3. Semelhanças
3.1. Elementos Únicos
AmbosTreeSeteHashSet garantem umduplicate-free collection of elements,, pois é parte da interfaceSet genérica:
@Test
public void givenHashSetAndTreeSet_whenAddDuplicates_thenOnlyUnique() {
Set set = new HashSet<>();
set.add("example");
set.add("example");
assertTrue(set.size() == 1);
Set set2 = new TreeSet<>();
set2.add("example");
set2.add("example");
assertTrue(set2.size() == 1);
}
3.2. Nãosynchronized
None of the described Set implementations are synchronized. Isso significa que se vários threads acessam umSet simultaneamente e pelo menos um dos threads o modifica, então ele deve ser sincronizado externamente.
3.3. Iteradores Fail-Fast
OIterators retornado porTreeSet eHashSet são fail-fast.
Isso significa que qualquer modificação deSet a qualquer momento após a criação deIterator lançará umConcurrentModificationException:
@Test(expected = ConcurrentModificationException.class)
public void givenHashSet_whenModifyWhenIterator_thenFailFast() {
Set set = new HashSet<>();
set.add("example");
Iterator it = set.iterator();
while (it.hasNext()) {
set.add("Awesome");
it.next();
}
}
4. Qual implementação usar?
Ambas as implementações cumprem o contrato da ideia de um conjunto, portanto, depende do contexto que implementação podemos usar.
Aqui estão alguns pontos rápidos a serem lembrados:
-
Se quisermos manter nossas entradas classificadas, precisamos ir para oTreeSet
-
Se valorizamos o desempenho mais do que o consumo de memória, devemos ir para oHashSet
-
Se temos pouca memória, devemos ir para oTreeSet
-
Se quisermos acessar elementos que são relativamente próximos uns dos outros de acordo com sua ordem natural, podemos considerarTreeSet porque tem maior localidade
-
O desempenho deHashSet pode ser ajustado usandoinitialCapacityeloadFactor, o que não é possível paraTreeSet
-
Se quisermos preservar o pedido de inserção e aproveitar o acesso em tempo constante, podemos usar oLinkedHashSet
5. Conclusão
Neste artigo, cobrimos as diferenças e semelhanças entreTreeSet eHashSet.
Como sempre, os exemplos de código para este artigo estão disponíveisover on GitHub.