Caio Oliveira
Caio Oliveira03/05/2023 21:01
Compartilhe

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!

    Compartilhe
    Comentários (0)