Java List, Set e ListIterator: dominando as coleções Java!

Java List, Set e ListIterator fazem parte da Classe Collections, responsável pela manipulação de conjuntos de dados e a iteração entre cada um de seus elementos internos. Saber o que é cada um deles é importantíssimo durante a implementação de sistemas em Java, sendo muito úteis no dia a dia profissional de uma pessoa programadora.

Apesar de serem conceitos relativamente simples e aplicações de fácil visualização, muitos iniciantes na programação perdem-se ao meio de tantas interfaces, tipos de dados, métodos e modelos possíveis de implementação — e isso é completamente normal para quem inicia agora no mundo do desenvolvimento.

Dominar esses conceitos significa ter uma série de problemas evitados e resoluções de conflitos, durante as diversas implementações que um sistema Java requer — de maneira muito mais rápida em relação àqueles que dispensam ou ignoram esse conhecimento.

Para ajudar você a entrar de cabeça nessa, e entender, de uma vez por todas sobre o que é e para que serve Java List, o Set e o ListIterator, entre outros métodos adjacentes a eles, trazemos este guia, com os principais conteúdos sobre o tema:

Tudo com exemplos práticos e uma explicação teórica dinâmica, tudo para ajudar você a ir bem na programação em Java! Então prepare sua estação e vamos lá!

O que é o Java list?

Um Java list pode ser definido como uma coleção ordenada de elementos. Esses elementos podem variar em relação ao tipo de dado — números inteiros, caracteres, booleanos ou decimais. Funciona como uma interface, que auxilia a própria interface das coleções, atuando na manipulação dos elementos internos e suas posições ocupadas.

Essa propriedade responsável pela ordenação de cada elemento em uma dada coleção é chamada índice — ou index, em inglês. Os elementos contidos em uma lista podem ser acessados por esses índices, além que ter a possibilidades de manipulá-los diretamente no Java list.

O Java list faz parte da estrutura do Java Collections Framework — um conjunto de classes e interfaces capazes de implementar estruturas de dados agrupados e utilizados durante o desenvolvimento de um sistema Java. Isso facilita na implantação de uma série de recursos que precisam ser escritos repetidamente — caso não tivéssemos essas facilidades.

Apesar de ser sempre referido como uma estrutura de dados — um framework — nos conteúdos especializados na área, o funcionamento do Java list está mais próximo do funcionamento de uma biblioteca.

Isso porque a estrutura de coleções utilizada na linguagem Java fornece diversas estruturas de interface para ambas, capazes de definir coleções e classes para as implementações dos recursos. Depois da versão 8 do Java, a interface list ganhou novos modelos de implementação, como novos métodos, como spliterator(), replaceall(), sort(), entre outros.

Vale lembrar que o início de uma lista em Java sempre terá seu início na posição 0 do índice. Por exemplo, em uma lista com os seguintes elementos:

A
B
C
D
E
F

O caracter “A” está ocupando a posição 0 da lista, enquanto o caracter “F” ocupa a posição 5 de uma lista com 6 elementos.

Uma outra informação importante de se destacar, é que o Java Collections Framework oferece suporte aos chamados generics — implementação adotada a partir da versão 5 do Java e oferece facilidades na implementação da linguagem, usado para especificar o tipo dos objetos armazenados em uma instância.

Portanto, ao implementarmos o uso de Java list com esse recurso, evitaremos erros de tipagem durante a execução do código, como uma “ClassCastException”, por exemplo — um tipo de erro bastante comum quando o tipo de dado inserido no conjunto não é o mesmo anteriormente especificado.

Qual a sintaxe do Java list?

Sendo uma como uma sub-interface da interface Collections, existem muitas maneiras de iniciarmos uma lista em Java. Uma delas é usando o método List, seguido do nome que queremos para nossa lista, igualando-a ao tipo de estrutura que queremos acompanhado com o operador “new”:

List nome = new estrutura da lista

Veja um exemplo aplicado:

List nome_da_lista = new ArrayList();
List nome_da_lista_b = new LinkedList();

Para iniciar nossa lista, usamos de vários métodos — por ser apenas uma interface, não podemos realizar o declaração da “variável lista” diretamente. Confira maiores detalhes e métodos para manipular uma lista na parte “Quais os métodos do Java list?” apresentada mais adiante neste guia.

Como criar um Java list?

Trazemos um exemplo prático para facilitar seu entendimento sobre aplicação de uma API de lista em Java, acompanhe:

import java.util.*;

public class Criando_uma_lista_com_ArrayList {
   public static void main(String[] args) {
       ArrayList<Integer> nossaLista = new ArrayList<>();

//Criando uma lista usando o método List:
       List lista_1 = new ArrayList<Integer>();

//Criando uma variável local para armazenar nossa lista:
       var list_2 = new ArrayList<Integer>();
   }
}

Como vemos, nesse exemplo, a criação de uma nova lista pode ser bem simples. Apresentamos aqui duas delas: uma usando o operador List para designar um nome e o tipo de dado de nossa lista. A outra implementamos armazenando a lista em uma variável — este último recurso apenas pode ser implementado a partir da versão 10 do Java.

Conheça o diagrama de classe Java list!

ArrayList, LinkedList, Vector e Stack são as principais maneiras de implementarmos listas no Framework Collections em Java, mas não são as únicas — a maioria são implementadas como classes.

A seguir mostramos um diagrama que representa a hierarquia entre as classes e funções dentro em relação à interface. 

DIAGRAMA – IMAGEM: Instruções para criação (se houver — caso negativo, apagar seção inteira)

Letras entre parênteses servem apenas para localização e ordem dos elementos.

Legenda:

> = aponta para (traço “bold” = complementa a função)

— = aponta para (traço “pontilhado” = estende a função

Indicação “X” = não aponta para outro/fim

a) Classe Java: Interface Java (List<Elemento>)// java.util — (b)

b) Classe Java: Interface Java (Coleção<Elemento>) // java.util > (c)

c) Classe Java: Interface Java (Iterador<elemento>) // java.util > X

d) Classe Java: Interface Java (Iterador<Elemento>) // java.util.concurrent > (a)

e) Classe Java: Interface Java (LinkedList<Elemento>) // java.util — (a)

f) Classe Java: Interface Java (CopyOnWriteArrayList<Elemento>) // java.util.concurrent > (a)

g) Classe Java: Interface Java (Stack<Elemento>) // java.util > (h)

h) Classe Java: Interface Java (Vector<Elemento>) // java.util — (i & a)

i) Classe Java: Interface Java (AbstractList<Elemento>) // java.util — (a)

j) Classe Java: Interface Java (ArrayList<Elemento>) // java.util — (i & a )

(referência do Diagrama: https://www.journaldev.com/11444/java-list )

Quais os métodos do Java list?

Como dissemos um pouco mais acima em nosso guia, os métodos para manipulação de lista estão presentes nas mais diversas formas, seja para alterar algum elemento de determinada posição, apagar toda uma lista ou apenas rotacionar sua ordem. Confira na sequência os principais deles:

Lista dos principais métodos usamos em Java list e descrição geral de cada um

  • boolean add(): adicionamos um elemento específico em uma lista, designamos apenas um objeto, o qual será posto no final da lista; 
  • boolean addAll(): adiciona todos os elementos de uma coleção para as posições finais de uma lista;
  • boolean contains(): retorna valor True ou False (verdadeiro ou falso, respectivamente) para dado elemento especificado presente ou não em uma dada lista;
  • boolean containsAll(): retorna verdadeiro nos casos que todos os elementos de uma coleção estão presente em uma determinada lista;
  • boolean equals(): compara se objetos específicos estão presentes em uma lista, retornando true nos casos em que há elementos iguais;
  • boolean isEmpty(): retorna True em caso de a lista que especificamos esteja vazia;
  • boolean remove(): remove a primeira ocorrência de um elemento de uma lista;
  • boolean removeAll(): remove todos os elementos de uma lista;
  • get(): realiza uma busca por um dado elemento em uma posição específica de uma lista;
  • indexOf(): retorna a primeira posição encontrada em que um elemento específico está no índice. Em casos que o elemento não exista, retorna o valor -1;
  • int hashcode(): retorna o valor do Hash de uma lista específica;
  • int lastIndexOf(): ao contrário do método Indexof(), este retorna a última posição em que um elemento especificado é encontrado em uma lista. Caso não esteja presente, o método retornará o valor -1;
  • int size(): retorna o número de elementos presentes em uma dada lista.
  • List <elemento>  subList(): busca todos os elementos contidos em um determinado escopo;
  • remove(): remove determinado elemento de uma lista;
  • set(): realoca ou introduz um elemento em uma lista;
  • toArray(): retorna um array com todos os elementos em uma lista em determinada ordem;
  • void add(): insere um elemento em determinada posição em uma lista;
  • void clear(): usado para remover todos os elementos de uma determinada lista;
  • void replaceAll(): substitui determinados elementos em uma lista por um elemento especificado;
  • void sort(): ordena os elementos de uma determinada lista.
  • Java List e ArrayList: qual a relação?

Entre o Java list e o ArrayList, é recomendado a opção pelo segundo, na maior parte das vezes. Isso porque o ArrayList faz de maneira mais dinâmica a manipulação de suas listas a serem implementadas. Podemos dizer que as boas práticas da linguagem recomendam muito o uso do ArrayList ao manipular esse tipo de estrutura de dados.

List<String> Nossa_nova_lista = new ArrayList<String>();

Fazendo dessa forma, quando declaramos o tipo de dado que a lista carregará, será muito mais simples realizarmos mudanças durante a implementação. Assim como sua estrutura será mais facilmente modificada quando houver a necessidade.

Caso declararmos diretamente a lista como um ArrayList, dificultariam quaisquer mudanças necessárias em nosso código que utilizem a estrutura ArrayList, nos trazendo problemas desnecessários durante a produção.

Set, HashSet e TreeSet: qual a relação?

De maneira resumida, um Set representa um conjunto de valores, o qual não possui elementos duplicados. Dois objetos Set serão idênticos caso contenham o mesmo número de elementos. A linguagem Java disponibiliza três tipos de implementação Set diferentes, o HashSet, o TreeSet e o LinkedHashSet.

Por sua vez, o HashSet é um conjunto em que os elementos não são ordenados ou sequer atendem a alguma ordenação. Um “hash” é um valor inteiro associado a cada objeto na linguagem Java. Seus principais propósitos estão na manipulação de “tabelas hash”, as quais são utilizadas em certas estruturas de dados — como um hashmap — e na capacidade de manipulação de elementos de tipo “null”.

Agora que entendemos isso, podemos dizer que um hashset é uma classe responsável por implementar a interface Set em uma instância hashmap. Caso queiramos usar algum Set com elementos de maneira ordenada, o recomendado é adicionar os elementos em um HashSet — para depois realizar a conversão para um TreeSet.

Já um Treeset é uma interface baseada em um treemap — estrutura responsável por representar visualmente dados hierárquicos por meio de troncos e galhos, lembrando o aspecto de uma árvore, como os comumente usados em diagramas. Seus elementos internos são ordenados de acordo com as interfaces implementadas, sendo dependentes dos construtores a que estão associados.

Java list vs Set: entenda as diferenças!

A principal diferença entre a interface Set e a List é a possibilidade de indexação dos elementos contidos em seus respectivos conjuntos. Assim como o TreeSet, um conjunto Set não pode ser buscado a partir de seu índice e conforme o posicionamento de cada elemento. 

Lembrando sobre a impossibilidade de elementos repetidos em Set, uma outra diferença importante entre essas interfaces. Diferente da interface List, a qual é ordenada e permite a adição de elementos duplicados.

Exemplo de uso do Java list!

Neste exemplo criamos uma lista com o método List, em seguida a inicializamos em um novo ArrayList e adicionamos um elemento em seu conjunto. Confira:

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

public class Main {
      public static void main(String[] args) {

            List <String> carros;
            carros = new ArrayList();
            carros.add("monza");
           System.out.println(carros);
           
      }

}

No lugar de criarmos uma instância para nossa lista com o ArrayList, poderíamos ter utilizado outras estruturas, como uma LinkedList, por exemplo.

Adicionando elementos em um Java list!

O método Add() é a maneira mais convencional de adicionarmos um elemento em nossa lista:

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

public class Main {

   static List<String> nossaLista = new ArrayList<String>();

   public static void main(String[] args) {
       nossaLista.add("um");
       nossaLista.add("dois");
       nossaLista.add("tres");

       for (String i : nossaLista) {
           System.out.println(i);
       }
   }
}

No exemplo, você pode verificar que declaramos nossa lista como um conjunto de dados do tipo “String”. Em seguida, inicializamos nossa List com o uso de um novo ArrayList. O método add() é implementado em cada vez que precisamos adicionar um elemento àquela lista. Nesse tipo de dado usamos aspas (“ ”) para identificar cada um dos elementos em add().

Lembrando que esse método apenas possibilita a inserção de um elemento por vez. Em, caso contrário, receberemos o seguinte erro no console:

Main.java:10: error: incompatible types: String cannot be converted to int
       nossaLista.add("um", "teste");

Como descobrir o tamanho da lista?

A maneira mais recomendada para sabermos o tamanho total de uma list em Java é utilizarmos o método size(). Com ele, é possível contarmos os elementos dentro de um dado ArrayList. Podemos citar aqui também o “.length” — método responsável pela contagem da capacidade de posições disponível em um array.

Como encontrar elementos em uma lista?

O método contains() é o mais indicado e mais comumente utilizado para essa tarefa. Esse método percorre o índice da lista e busca o dado designado. Ele retorna um valor booleano, ou seja, verdadeiro ou falso para em casos de conter ou não, respectivamente, os elementos na lista.

Poucos têm a compreensão disso, mas um dado do tipo “string” pode ser uma lista de caracteres. Veja no exemplo como usando o método contains() para buscar elementos em uma string, que neste caso usamos “Betrybe”:

//Sintaxe do método contains():
//public boolean contains(CharSequence chars)

public class Main {
  public static void main(String[] args) {
   String mString = "Betrybe";
   System.out.println(mString.contains("A"));
   System.out.println(mString.contains("B"));
   System.out.println(mString.contains("Y"));
  }
}

Perceba que o método é sensível à diferença entre maiúsculas e minúsculas. A saída do console para esse código será:

false
true
false

Como remover elementos de uma lista?

O método mais utilizado para remover determinados objetos de um conjunto, seja uma Lista ou um Set é o método remove(). Explicando de maneira resumida, o recurso remove() funciona iterando o conjunto de dados e verificando se o especificado faz parte. Em caso afirmativo, o método retira esse elemento daquele conjunto.

import java.util.*;
 
public class SetDemo {
   public static void main(String args[])
   {
//Criando uma nova lista em um ArrayList
       List<String> lista = new ArrayList<String>();
 
//Usando add() para adicionar elelentos
       lista.add("Venha");
       lista.add("para a");
       lista.add("Trybe! ");
       lista.add("Be");
       lista.add("Trybe");
 
       // mostrando nossa lista
       System.out.println("lista: " + lista);
 
       // Removendo elementos com remove() 
       lista.remove("Be");
       lista.remove("Trybe");
        lista.remove("Outro elemento");


       //Imprimindo a lista depois da remoção:
       System.out.println("l Lista de palavras depois do processo de remove(): "+ lista);
   }
}

Como vemos acima, o uso de um objeto que não exista no conjunto não interfere na implementação do método remove(). A saída desse código no console será:

Lista de palavras: [Venha, para a, Trybe! , Be, Trybe]
Lista de palavras depois do processo de remove() [Venha, para a, Trybe! ]

Como converter array em list?

O método mais simples é o que criar uma lista vazia, percorrê-la e transcrever cada um dos elementos contidos no array e passá-los para a lista:

import java.util.*;

public class Main {
    public static void main(String args[]) {
        String[] Array_ex = new String[] { "A", "B", "C" };
        List<String> lista_Ex = new ArrayList<>();
        for (int i=0; i<Array_ex.length; i++){
            lista_Ex.add(myArray[i]);
        }
        System.out.println(myList);
    }

Ou podemos usar um método, o Arrays.asList(arr). Com ele, fazemos a conversão direta de uma para outro:

import java.util.*;

public class MyClass {
    public static void main(String args[]) {
        String[] Array_ex = new String[] { "A", "B", "C" };
        List<String> lista_Ex = Arrays.asList(Array_ex );
        System.out.println(lista_Ex );
    }
}

Como converter list em array?

Para converter uma lista em array, usamos um método já existente em Java, o to Array(). Com ele, fazendo a mesma coisa que o Arrays.asList(arr) faz, mas o inverso — convertemos as listas em arrays:

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

public class ConvertendoListsParaArrays {

    public static void main(String[] args) {
        List<String> lista_Nomes = new ArrayList<String>();
        lista_Nomes.add("Jan");
        lista_Nomes.add("Jaci");
        lista_Nomes.add("Alex");
        lista_Nomes.add("Andrea");

        String[] array_Nomes = lista_Nomes.toArray(new String[0]);

        System.out.println(lista_Nomes );
    }
}

Ordenando um Java list!

Ordenar uma lista significa organizá-la de uma maneira natural — entenda por “natural” o uso de uma ordenação alfabética (de A à Z) ou numérica (menor para o maior). Para fazer isso em nossas listas em Java, a melhor maneira é usar o método sort(), uma classe das coleções incluída no pacote java.util. Veja os exemplos:

import java.util.ArrayList;
import java.util.Collections;

public class Main {
  public static void main(String[] args) {
   ArrayList<String> carros = new ArrayList<String>();
   cars.add("Fusca");
   cars.add("Kombi");
   cars.add("Chevette");
   cars.add("Opala");
    
   Collections.sort(carros);

   for (String i : carros) {
     System.out.println(i);
   }
  }
}

A saída deste código será a seguinte:

Chevette
Fusca
Kombi
Opala

Você pode repetir esse exemplo como exercício, troque o dos dados (e o tipo deles) para inteiros e veja que o método sort() funciona da mesma forma. 

Conheça a interface Java listiterator!

A interface ListIterator oferece uma série de métodos capazes de realizar várias operações nos elementos de uma lista. Na interface List usa o método listiterator para retornar a instância atual do índice na lista. Entre os métodos que encontramos, são os principais:

  • set (): com ele, podemos substituir o elemento que foi retornado por next() ou previous() pelo elemento que especificamos;
  • get(): aciona o elemento especificado no índice;
  • previousIndex (): retorna o índice anterior do elemento;
  • remove (): remove o elemento
  • previous(): retorna o elemento posterior ao índice especificado na lista;
  • next (): retorna o próximo elemento iterado na lista; 
  • hasNext (): retorna verdadeiro se existir um elemento na lista 

Confira neste exemplo a seguir a aplicação de um list Iterator e de alguns métodos dos quais apresentamos:

import java.util.ArrayList;
import java.util.ListIterator;

public class Main {
   public static void main(String[] args) {
// Definindo nossa lista a partir de um ArrayList:
       ArrayList<Integer> num = new ArrayList<>();
       num.add(1);
       num.add(3);
       num.add(2);
       System.out.println("Lista " + num);

//Intanciando o ListIterator:
       ListIterator<Integer> iterar = num.listIterator();
//Usando nextIndex() e o listIterator:
       int indice = iterar.nextIndex();
       System.out.println("Position of Next Element: " + indice);
//Usando next() e o listIterator:
       int num1 = iterar.next();
       System.out.println("próximo elemento: " + num1);
//Usando hasNext():
       System.out.println("Sobrou algum elemento? " + iterar.hasNext());
   }
}

Durante todo nosso guia, exploramos os principais detalhes que são relacionados com a implementação de um Java list. Vimos as diferentes interfaces, contidas no framework responsável por operar as coleções na linguagem Java, em seus usos práticos mais comuns, de maneira simples e descomplicada.

Exploramos a teoria de maneira dinâmica, aplicando os conceitos aprendidos em códigos que funcionam e mostram como cada recurso opera durante suas aplicações. Aprendemos com converter listas em outras estruturas e também aprendemos a fazer ao contrário, converter outras estruturas em listas.

Podemos entender como organizar nossas listas e cada elemento contido nelas, assim como é o funcionamento de diversos métodos pertencente às interfaces que trabalhamos em detalhes, muitas vez de maneira aplicada. Portanto, esperamos que nosso guia sobre o Java List tenha sido uma ótima fonte de informação para as pessoas iniciantes no desenvolvimento em Java.

Se você quer aprender mais sobre a linguagem Java e se preparar para o mercado de desenvolvimento com a Trybe, que tal entrar em contato conosco e saber mais sobre como podemos ajudar você na sua evolução na área de desenvolvimento? Faça agora mesmo sua inscrição em nosso processo seletivo e prepare-se.