CodeGym /Cursos /JAVA 25 SELF /Operações union, intersection, difference

Operações union, intersection, difference

JAVA 25 SELF
Nível 32, Lição 2
Disponível

1. Operação union (união de conjuntos)

Em Java, para representar conjuntos usa-se a interface Set<T>. Diferentemente de listas (List), conjuntos garantem a unicidade dos elementos e, em geral, não se preocupam com a ordem (a menos que você use implementações especiais, como LinkedHashSet). As implementações mais populares — HashSet e TreeSet. Sua principal tarefa — determinar rapidamente a presença de um elemento e garantir a ausência de duplicatas.

Quando usar conjuntos?

  • Quando a unicidade é importante: por exemplo, a lista de todos os usuários únicos que visitaram o site.
  • Quando é preciso verificar rapidamente a presença de um elemento: o método contains em HashSet geralmente funciona em tempo constante.
  • Quando for necessário executar operações típicas sobre coleções: união, interseção, diferença.

Union — é a união de dois ou mais conjuntos: o resultado contém todos os elementos de ambos os conjuntos de origem (sem repetições).

Exemplo na prática

Suponha que temos dois conjuntos de alunos que frequentam os clubes “Robótica” e “Programação”:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Precisamos obter o conjunto de todos os alunos que frequentam pelo menos um clube.

Solução com Stream API

A forma mais direta — concatenar ambos os streams e coletá-los em um Set:

Set<String> all = Stream.concat(
        robotics.stream(),
        programming.stream()
    ).collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha]

Explicação:

  • Stream.concat concatena dois streams.
  • collect(Collectors.toSet()) coleta os elementos em um conjunto (removendo duplicatas automaticamente).

Alternativa: mais de dois conjuntos

Se tivermos três ou mais clubes, use Stream.of e flatMap:

Set<String> math = Set.of("Zhenya", "Vika", "Boris");

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha, Zhenya]

Por que Set?
Porque Set remove duplicatas automaticamente. Se você coletar em uma List, os mesmos nomes aparecerão várias vezes.

2. Operação intersection (interseção de conjuntos)

Intersection — são os elementos que existem simultaneamente em ambos os conjuntos.

Exemplo na prática

Encontrar alunos que frequentam tanto “Robótica” quanto “Programação”:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Solução com Stream API:

Set<String> both = robotics.stream()
    .filter(programming::contains)
    .collect(Collectors.toSet());

System.out.println(both); // [Vika]

Explicação:
Percorremos todos os participantes de “Robótica” e filtramos apenas aqueles que estão em “Programação”. O resultado é um conjunto com os nomes que aparecem em ambos os clubes.

Alternativa (sem Stream API)

É possível usar o método incorporado retainAll (ele modifica o conjunto atual):

Set<String> intersection = new HashSet<>(robotics);
intersection.retainAll(programming);
System.out.println(intersection); // [Vika]

Mas, no tema de Stream API, focamos nos streams.

3. Operação difference (diferença de conjuntos)

Difference — são os elementos do primeiro conjunto que não existem no segundo.

Exemplo na prática

Encontrar alunos que frequentam somente “Robótica”, mas não “Programação”:

Set<String> robotics = Set.of("Anya", "Boris", "Vika");
Set<String> programming = Set.of("Vika", "Gleb", "Dasha");

Solução com Stream API:

Set<String> onlyRobotics = robotics.stream()
    .filter(name -> !programming.contains(name))
    .collect(Collectors.toSet());

System.out.println(onlyRobotics); // [Anya, Boris]

Explicação:
Filtramos os participantes de “Robótica”, deixando apenas aqueles que não estão em “Programação”.

Alternativa (sem Stream API)

Set<String> difference = new HashSet<>(robotics);
difference.removeAll(programming);
System.out.println(difference); // [Anya, Boris]

4. Tarefas práticas: processamento de listas de usuários

Tarefa 1: Encontrar alunos que frequentam apenas um clube

Precisamos saber quem frequenta apenas “Robótica” ou apenas “Programação”, mas não ambos ao mesmo tempo. Isso é a diferença simétrica (xor para conjuntos):

Set<String> onlyOne = Stream.concat(
        robotics.stream().filter(name -> !programming.contains(name)),
        programming.stream().filter(name -> !robotics.contains(name))
    ).collect(Collectors.toSet());

System.out.println(onlyOne); // [Anya, Boris, Gleb, Dasha]

Tarefa 2: Lista de todos os alunos únicos de vários clubes

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Anya, Boris, Vika, Gleb, Dasha, Zhenya]

Tarefa 3: Encontrar alunos que não frequentam nenhum clube

Suponha que temos a lista de todos os alunos da turma:

Set<String> allStudents = Set.of("Anya", "Boris", "Vika", "Gleb", "Dasha", "Zhenya", "Igor’", "Katya");

Precisamos saber quem não frequenta nenhum clube:

Set<String> attendees = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

Set<String> notInAny = allStudents.stream()
    .filter(name -> !attendees.contains(name))
    .collect(Collectors.toSet());

System.out.println(notInAny); // [Igor’, Katya]

5. Observações importantes: equals, hashCode e desempenho

Por que é importante implementar corretamente equals e hashCode?

Todas as operações com conjuntos (Set) dependem da correção dos métodos equals e hashCode. Se você armazena objetos de sua própria classe (por exemplo, Student), então é obrigatório sobrescrever esses métodos; caso contrário, as comparações não funcionarão corretamente.

Exemplo:

class Student {
    String name;
    int age;

    // Não se esqueça de sobrescrever equals e hashCode!
}

Se isso não for feito, dois alunos com os mesmos nomes e idades serão considerados objetos diferentes para o Set.

Por que é melhor usar Set, e não List?

  • A operação contains em Set é rápida (geralmente, tempo constante).
  • Em List, a busca de um elemento ocorre em tempo linear, o que pode ser crítico para coleções grandes.
  • Para operações sobre conjuntos (union, intersection, difference), Set é muito mais eficiente e lógico.

6. Erros comuns ao trabalhar com operações sobre conjuntos

Erro nº 1: Usar List em vez de Set para operações sobre conjuntos. Se você coleta elementos em uma List, as duplicatas não são removidas, e a operação contains é lenta. Para union/intersection/difference, use Set.

Erro nº 2: equals/hashCode não implementados para objetos. Se você armazena em um Set objetos de sua própria classe, mas não sobrescreveu os métodos equals e hashCode, então a interseção e a diferença se comportarão “estranhamente” — objetos que, em essência, são iguais não serão considerados iguais.

Erro nº 3: Modificar a coleção durante o stream. Se você tentar modificar o Set original diretamente dentro do stream (por exemplo, adicionando ou removendo elementos), você terá um ConcurrentModificationException. Sempre trabalhe com um novo conjunto.

Erro nº 4: Perda de ordem não óbvia. HashSet não garante a ordem dos elementos. Se a ordem for importante — use LinkedHashSet ou TreeSet.

Erro nº 5: Usar Stream.concat para mais de duas coleções. Stream.concat concatena apenas dois streams. Para uma quantidade maior, use Stream.of(...) e flatMap.

Erro nº 6: Problemas com null. Conjuntos não gostam de valores null, especialmente se você usar Set.of(...) — ele não permite null. Para lidar com null, use outras implementações ou filtre os valores antecipadamente.

1
Tarefa
JAVA 25 SELF, nível 32, lição 2
Bloqueado
Identificação de suspeitos únicos por diferentes fontes 🕵️‍♂️
Identificação de suspeitos únicos por diferentes fontes 🕵️‍♂️
1
Tarefa
JAVA 25 SELF, nível 32, lição 2
Bloqueado
Catalogação de artefatos de diferentes escavações arqueológicas 🏺
Catalogação de artefatos de diferentes escavações arqueológicas 🏺
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION