Como Verificar se uma Lista Contém Todos os Elementos de Outra Lista em Java

JavaBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como verificar se uma lista contém todos os elementos de outra lista em Java. Esta é uma tarefa fundamental ao trabalhar com coleções e entender as relações entre conjuntos de dados.

Exploraremos o método containsAll() eficiente fornecido pelo framework Java Collections para uma verificação rápida de subconjunto. Para solidificar sua compreensão, você também aprenderá como realizar essa verificação manualmente usando um loop. Finalmente, testaremos o comportamento desses métodos com casos extremos, incluindo listas vazias e nulas, para garantir um código robusto.

Usar containsAll() para Verificação de Subconjunto

Nesta etapa, exploraremos como verificar se uma lista é um subconjunto de outra usando o método containsAll() em Java. Esta é uma tarefa comum ao trabalhar com coleções, e containsAll() fornece uma maneira conveniente de realizar essa verificação.

Primeiro, vamos criar um novo arquivo Java chamado SubsetCheck.java em seu diretório ~/project. Você pode fazer isso usando o explorador de arquivos WebIDE à esquerda. Clique com o botão direito na área ~/project, selecione "Novo Arquivo" e digite SubsetCheck.java.

Agora, abra o arquivo SubsetCheck.java no editor e adicione o seguinte código:

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubset = mainList.containsAll(subList);

        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList? " + isSubset);

        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList
        boolean isAnotherSubset = mainList.containsAll(anotherList);

        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList? " + isAnotherSubset);
    }
}

Vamos detalhar o código:

  • Importamos ArrayList e List do pacote java.util para trabalhar com listas.
  • Criamos dois objetos ArrayList: mainList e subList.
  • Adicionamos alguns elementos de string a ambas as listas.
  • A parte chave é mainList.containsAll(subList). Este método verifica se mainList contém todos os elementos presentes em subList. Ele retorna true se contiver, e false caso contrário.
  • Armazenamos o resultado em uma variável booleana isSubset e o imprimimos.
  • Em seguida, criamos anotherList que contém um elemento não presente em mainList e realizamos a mesma verificação para ver o resultado quando não é um subconjunto.

Salve o arquivo SubsetCheck.java (Ctrl+S ou Cmd+S).

Agora, abra o Terminal na parte inferior do WebIDE. Certifique-se de estar no diretório ~/project. Caso contrário, use o comando cd ~/project.

Compile o código Java usando o comando javac:

javac SubsetCheck.java

Se não houver erros de compilação, você deverá ver um arquivo SubsetCheck.class criado no diretório ~/project.

Finalmente, execute o programa Java compilado usando o comando java:

java SubsetCheck

Você deverá ver uma saída semelhante a esta:

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList? false

Esta saída confirma que subList é de fato um subconjunto de mainList porque todos os seus elementos estão presentes em mainList, enquanto anotherList não é um subconjunto porque "Grape" não está em mainList.

Verificar com Loop Manual

Na etapa anterior, usamos o método containsAll() conveniente para verificar um subconjunto. Embora containsAll() seja eficiente, é útil entender como você realizaria essa verificação manualmente usando um loop. Isso aprofundará sua compreensão de como os métodos de coleção podem funcionar internamente.

Vamos adicionar um novo método ao nosso arquivo SubsetCheck.java para realizar a verificação de subconjunto manualmente. Abra ~/project/SubsetCheck.java no editor WebIDE.

Adicione o seguinte método dentro da classe SubsetCheck, mas fora do método main:

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }

Este novo método isSubsetManual recebe duas listas como entrada. Em seguida, ele percorre cada element em subList. Dentro do loop, ele verifica se mainList contém o element atual usando o método contains(). Se encontrar até mesmo um elemento em subList que não está em mainList, ele sabe imediatamente que subList não é um subconjunto e retorna false. Se o loop terminar sem encontrar nenhum elemento em subList que esteja faltando em mainList, significa que todos os elementos estão presentes, e o método retorna true.

Agora, vamos chamar este novo método de nosso método main para comparar seu resultado com containsAll(). Modifique o método main em SubsetCheck.java para incluir chamadas para isSubsetManual:

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

Salve o arquivo SubsetCheck.java modificado.

Agora, compile o código atualizado no Terminal:

javac SubsetCheck.java

E execute o programa novamente:

java SubsetCheck

Você deverá ver uma saída semelhante a esta, mostrando que tanto o método containsAll() quanto nosso método de loop manual produzem os mesmos resultados:

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

Esta etapa demonstra que você pode obter o mesmo resultado que containsAll() iterando pelo potencial subconjunto e verificando a presença de cada elemento na lista principal. Embora containsAll() seja geralmente preferido por sua concisão e possíveis otimizações de desempenho na biblioteca Java, a compreensão da abordagem manual é valiosa para o aprendizado.

Testar com Listas Vazias e Nulas

Nesta etapa, exploraremos como o método containsAll() e nosso método de verificação manual se comportam ao lidar com listas vazias e valores null. Entender esses casos extremos é importante para escrever um código robusto.

Abra o arquivo ~/project/SubsetCheck.java no editor WebIDE. Adicionaremos mais casos de teste ao método main.

Modifique o método main para incluir verificações com listas vazias e uma lista null:

import java.util.ArrayList;
import java.util.List;

public class SubsetCheck {

    public static void main(String[] args) {
        // Create the main list
        List<String> mainList = new ArrayList<>();
        mainList.add("Apple");
        mainList.add("Banana");
        mainList.add("Cherry");
        mainList.add("Date");

        // Create a potential subset list
        List<String> subList = new ArrayList<>();
        subList.add("Banana");
        subList.add("Cherry");

        // Check if subList is a subset of mainList using containsAll()
        boolean isSubsetContainsAll = mainList.containsAll(subList);
        // Check if subList is a subset of mainList using manual loop
        boolean isSubsetManualCheck = isSubsetManual(mainList, subList);


        // Print the result
        System.out.println("Main List: " + mainList);
        System.out.println("Sub List: " + subList);
        System.out.println("Is subList a subset of mainList (containsAll)? " + isSubsetContainsAll);
        System.out.println("Is subList a subset of mainList (manual check)? " + isSubsetManualCheck);


        // Create another list that is not a subset
        List<String> anotherList = new ArrayList<>();
        anotherList.add("Banana");
        anotherList.add("Grape"); // Grape is not in mainList

        // Check if anotherList is a subset of mainList using containsAll()
        boolean isAnotherSubsetContainsAll = mainList.containsAll(anotherList);
         // Check if anotherList is a subset of mainList using manual loop
        boolean isAnotherSubsetManualCheck = isSubsetManual(mainList, anotherList);


        // Print the result for the second check
        System.out.println("\nAnother List: " + anotherList);
        System.out.println("Is anotherList a subset of mainList (containsAll)? " + isAnotherSubsetContainsAll);
        System.out.println("Is anotherList a subset of mainList (manual check)? " + isAnotherSubsetManualCheck);

        // --- Test with Empty Lists ---

        // Create an empty list
        List<String> emptyList = new ArrayList<>();

        // Check if emptyList is a subset of mainList
        boolean isEmptySubsetContainsAll = mainList.containsAll(emptyList);
        boolean isEmptySubsetManualCheck = isSubsetManual(mainList, emptyList);

        System.out.println("\nEmpty List: " + emptyList);
        System.out.println("Is emptyList a subset of mainList (containsAll)? " + isEmptySubsetContainsAll);
        System.out.println("Is emptyList a subset of mainList (manual check)? " + isEmptySubsetManualCheck);

        // Check if mainList is a subset of emptyList (should be false unless mainList is also empty)
        boolean isMainSubsetEmptyContainsAll = emptyList.containsAll(mainList);
        boolean isMainSubsetEmptyManualCheck = isSubsetManual(emptyList, mainList);

        System.out.println("Is mainList a subset of emptyList (containsAll)? " + isMainSubsetEmptyContainsAll);
        System.out.println("Is mainList a subset of emptyList (manual check)? " + isMainSubsetEmptyManualCheck);

        // --- Test with Null List ---

        // Create a null list
        List<String> nullList = null;

        // Check with nullList using containsAll()
        System.out.println("\nNull List: " + nullList);
        try {
            boolean isNullSubsetContainsAll = mainList.containsAll(nullList);
            System.out.println("Is nullList a subset of mainList (containsAll)? " + isNullSubsetContainsAll);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using containsAll() resulted in: " + e);
        }

        // Check with nullList using manual loop
         try {
            boolean isNullSubsetManualCheck = isSubsetManual(mainList, nullList);
            System.out.println("Is nullList a subset of mainList (manual check)? " + isNullSubsetManualCheck);
        } catch (NullPointerException e) {
            System.out.println("Checking with nullList using manual check resulted in: " + e);
        }
    }

    // Method to manually check if subList is a subset of mainList
    public static boolean isSubsetManual(List<String> mainList, List<String> subList) {
        // Add a check for null subList in the manual method
        if (subList == null) {
             throw new NullPointerException("Sub list cannot be null for manual check.");
        }
        // Iterate through each element in the subList
        for (String element : subList) {
            // If the mainList does NOT contain the current element from subList,
            // then subList is not a subset, and we can return false immediately.
            if (!mainList.contains(element)) {
                return false;
            }
        }
        // If we have checked all elements in subList and found them all in mainList,
        // then subList is a subset.
        return true;
    }
}

Adicionamos seções para testar com uma emptyList e uma nullList. Observe que, para os testes nullList, envolvemos as chamadas em blocos try-catch. Isso ocorre porque tentar chamar métodos em um objeto null (como mainList.containsAll(nullList)) resultará em uma NullPointerException. Nosso método manual também precisa lidar com o caso em que subList é null, então adicionamos uma verificação no início de isSubsetManual.

Salve o arquivo SubsetCheck.java modificado.

Compile o código atualizado no Terminal:

javac SubsetCheck.java

E execute o programa novamente:

java SubsetCheck

Você deverá ver uma saída semelhante a esta:

Main List: [Apple, Banana, Cherry, Date]
Sub List: [Banana, Cherry]
Is subList a subset of mainList (containsAll)? true
Is subList a subset of mainList (manual check)? true

Another List: [Banana, Grape]
Is anotherList a subset of mainList (containsAll)? false
Is anotherList a subset of mainList (manual check)? false

Empty List: []
Is emptyList a subset of mainList (containsAll)? true
Is emptyList a subset of mainList (manual check)? true
Is mainList a subset of emptyList (containsAll)? false
Is mainList a subset of emptyList (manual check)? false

Null List: null
Checking with nullList using containsAll() resulted in: java.lang.NullPointerException
Checking with nullList using manual check resulted in: java.lang.NullPointerException: Sub list cannot be null for manual check.

Na saída, observe o seguinte:

  • Uma lista vazia é considerada um subconjunto de qualquer lista (incluindo outra lista vazia). Tanto containsAll() quanto nosso método manual identificam isso corretamente.
  • Uma lista não vazia não é um subconjunto de uma lista vazia.
  • Passar uma lista null para containsAll() ou nosso método manual (sem uma verificação nula) resulta em uma NullPointerException. Isso destaca a importância de lidar com valores null potenciais em seu código.

Esta etapa conclui nossa exploração da verificação de subconjuntos em listas Java. Você aprendeu como usar o método containsAll() integrado, como realizar a verificação manualmente e como esses métodos se comportam com listas vazias e nulas.

Resumo

Neste laboratório, aprendemos como verificar se uma lista contém todos os elementos de outra lista em Java. Nos concentramos principalmente no uso do método containsAll() conveniente fornecido pela interface Collection.

Demonstramos como usar containsAll() com listas de exemplo e observamos seu comportamento para casos de subconjunto e não subconjunto. Este método oferece uma maneira concisa e eficiente de realizar esta tarefa comum de comparação de listas.