Um breve papo sobre Coleções (Pt. 3) - Sets
Agora que esclarecemos o básico sobre o funcionamento dos Comparators, podemos falar sobre a outra Interface usada para criar uma coleção de objetos, a Set
O que é um Set?
Set (Conjunto) segue a definição matemática de conjunto, onde cada elemento presente é único.
Principais características:
- Não permite elementos duplicados: Um Set não pode conter elementos duplicados. Se você tentar adicionar um elemento que já está presente no conjunto, a operação será ignorada.
- Não garante ordem: a ordem dos elementos em um Set pode variar entre diferentes implementações e entre diferentes execuções do programa. Portanto, não é seguro depender da ordem dos elementos em um conjunto.
- Permite operações de conjuntos: o Set inclui métodos para realizar operações comuns de conjuntos, como união(addAll), interseção (retainAll) e diferença(removeAll).
- Herda as funcionalidades da interface Collection: a interface Set estende a interface Collection, portanto, ela herda todos os métodos definidos na interface Collection, como size(), isEmpty(), add(), remove(), contains() e muitos outros.
Princiapis implementações da Interface
Como se trata de uma interface, evidentemente temos como suas principais implementações:
- HashSet
- TreeSet
- LinkedHashSet
Quais as diferenças entre elas?
- HashSet: É uma implementação baseada em tabela de hash, o que significa que os elementos são armazenados em um array e a pesquisa é realizada através de uma função de hash, que é uma função matemática que garante a unicidade de cada objeto, associando o objeto em questão a um número inteiro. Geralmente ele está intimamente ligado ao método equals. Para entendermos melhor, vamos ver os métodos equals e hashCode implementados em uma classe:
public class Pessoa {
private String nome;
private int idade;
public Pessoa(String nome, int idade) {
this.nome = nome;
this.idade = idade;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Pessoa)) {
return false;
}
Pessoa pessoa = (Pessoa) obj;
return pessoa.nome.equals(this.nome) && pessoa.idade == this.idade;
}
@Override
public int hashCode() {
int result = 10;
result = 31 * result + nome.hashCode();
result = 31 * result + idade;
return result;
}
}
Note que cada objeto gera um único hashCode() de acordo com seus parâmetros internos.
- TreeSet: É uma implementação baseada em árvore, onde os elementos são organizados em uma árvore binária e mantidos em ordem natural (ou em ordem definida pelo Comparator fornecido).
- LinkedHashSet: Mantém a ordem de inserção dos elementos em um HashSet, utilizando a estrutura de lista encadeada
Vamos a um exemplo prático:
public class Main {
public static void main(String[] args) {
HashSet<String> set1 = new HashSet<>();
set1.add("Mario");
set1.add("Kart");
set1.add("Donkey Kong");
set1.add("Anabelle");
System.out.println(set1);
TreeSet<String> set2 = new TreeSet<>();
set2.add("Kart");
set2.add("Mario");
set2.add("Donkey Kong");
set2.add("Anabelle");
System.out.println(set2);
LinkedHashSet<String> set3 = new LinkedHashSet<>();
set3.add("Kart");
set3.add("Mario");
set3.add("Donkey Kong");
set3.add("Anabelle");
System.out.println(set3);
}
}
Você verá que apenas LinkedHashSet preserva a ordem de inserção !
Exercício:
Dado os Sets A = [1,4,5,6,9], B = [1,9], C = [9,13]
Faça as seguintes operações de conjunto:
- A diff B
- B U C
- A ∩ B ∩ C
- (A diff B) U A
That's All Folks!