A infraestrutura Collections ou coleção do Java disponibiliza os recursos de estrutura de dados, ou seja, contem as principais funcionalidades para se trabalhar com conjunto de elementos (coleções).

Segundo Deitel com as Collections "você utiliza estruturas de dados existentes, sem se preocupar com a maneira como são implementadas", para ter uma idéia, no artigo Pilhas: Fundamentos e implementação da estrutura em Java (//www.devmedia.com.br/pilhas-fundamentos-e-implementacao-da-estrutura-em-java/28241) escrito por mim, eu trato do processo de implementação de pilha manualmente, e mesmo sendo uma pilha simples, há a necessidade em pensar no seu funcionamento e como fazer toda a implementação.

O Java possui uma interface raiz denominada Collections, com disponibilidade de outras estruturas para ser utilizada, em geral as Collections são estruturas dinâmicas, ou seja, podem crescer conforme a necessidade de expansão, diferente do array por exemplo. O conjunto de interfaces e classes concretas que fazem parte da API Collection pode ser Figura 1, os quadros em cinza representam as Interfaces de coleções e os quadros em azul representam classes concretas.

Collections

Figura 1: Collection

Quanto mais genérica, por exemplo a Interface Collection, possui menos acoplamento, quanto mais especifica, mais acoplamento. Segundo Silveira et. al. "Trabalhar com coleções, escolher a implementação certa para cada caso é uma tarefa difícil. Cada uma delas, como ArrayList, LinkedList ou HashSet, é melhor para resolver determinadas categorias de problemas"

Outro ponto, é que quanto mais genérica, mais estável, pois possui menos chances de modificação, pois dela, outras classes dependem, quanto mais especifica, menos estável e mais modificações pode existir.

Há ainda classes que implementam a interface Map ao invés da Collection, mesmo assim, faz parte da API Collection, veja figura 2.

Map

Figura 2: Map

Vamos entender que Collection é o topo da API Collections, disponível no pacote java.util. Collections é a API que oferece diversas coleções (interfaces e classes concretas).

As Interfaces e classes concretas que implementam a interface Collection, terão obrigatoriamente que fazer a implementação de diversos métodos que manipulam coleções de dados, tais como adicionar e remover elementos.

As Collections podem ser organizadas e ou ordenadas, mas qual a diferença?

Algumas Collections são organizadas, ou seja, garante que as coleções serão percorridas na mesma ordem em que os elementos foram inseridos, já quando a Collection é ordenada, esta possui métodos, regras para ordenação dos elementos.

Organizada: LinkedHashSet, ArrayList, Vector, LinkedList, LinkedHashMap

Não organizada: HashSet, TreeSet, PriorityQueue, HashMap, HashTable, TreeMap

Ordenada: TreeSet, PriorityQueue, TreeMap

Não ordenada: HashSet, LinkedHashSet, ArrayList, Vector, LinkedList, HashMap, HashTable, LinkedHashMap.

Alguns conceitos para utilizar as Collections que pode ser realmente de grande ajuda.

Generics

O padrão das Collections é aceitar Generics, ou seja, aceitar qualquer tipo de elemento, inclusive elementos diferentes: Double, String, Integer, ou outro objeto que desejar.

Mas é possível especificar o tipo a ser aceito, da seguinte forma:

Listagem 1: Exemplo de Generics

//Sintax:
Tipo<tipo> nomeObjeto = new Tipo<tipo>();
///Ex.:
List<String> minhaLista = new ArrayList<String>();

For-each

O For-each é um ciclo for, mas que é adaptado para utilização em Collections e outras listas. Ele serve para percorrer todos os elementos de qualquer Collection contida na API Collections.

Listagem 2: For-each

//Sintaxe:

for(tipo elemento:tipo)

//Ex.:

List<Integer> minhaLista = new ArrayList<Integer>();
		minhaLista.add(1);
		minhaLista.add(2);
		for (Integer listaElementos : minhaLista) {
			System.out.println(listaElementos);
		}

Iterator

O iterator é uma interface disponível no pacote java.util que permite percorrer coleções da API Collection, desde que tenham implementado a Collection, fornecendo métodos como o next(), hasnext() e remove().

Listagem 3: Exemplo de Iterator

List<Integer> minhaLista = new ArrayList<Integer>();
		minhaLista.add(1);
		minhaLista.add(2);
		Iterator iMinhaLista = minhaLista.iterator();

		for(Integer listaElementos: minhaLista){
			System.out.println(iMinhaLista.next());
		}

As Collections possuem padrões para uso, vamos ver um exemplo no código a seguir:

Listagem 4: Padrões de Collections

Set<Integer> meuSet = new HashSet<Integer>();
		meuSet.add(1);
		meuSet.add(2);
		meuSet.add(3);
		meuSet.add(1);
		Iterator<Integer> iMeuSet = meuSet.iterator();
		while(iMeuSet.hasNext()){
			System.out.println(iMeuSet.next());
		}

Este código por utilizar o Set, ao exibir os dados, vai ter como resultado 1, 2 e 3, se utilizar-mos o List, teriamos como resultado 1,2,3,1 por que?

Bem cada tipo apresentado, tem uma forma de trabalhar, vamos entender cada uma delas:

Set: Não aceita itens duplicados, aceita nulos, não possui índice, rápido para inserir e pesquisar elementos;

HashSet: esta é uma implementação concreta de Set não organizada, ou seja, os elementos são percorridos aleatoriamente, e também não é ordenada, não há regras de ordenação. Além disso, assim como Set, não aceita itens duplicados.

TreeSet: implementação concreta de Set organizada, mas também não aceita itens duplicados.

TreeSet: Também é uma implementação concreta, não aceitando itens duplicados, mas é ordenada.

List: Aceita itens duplicados, organizada e todas as implementações seguem este padrão, elementos percorridos por ordem ser inserção, não ordenada, aceita nulo, trabalha com índices da mesma forma que os arrays, é rápido para inserir elementos, mas um pouco mais lento que o Set, já as pesquisas são mais lentas que o Set.

ArrayList: implementação concreta de List, aceita itens duplicados e seu funcionamento é semelhante a um array convencional, com a principal diferença de ser dinamica, ou seja, pode crescer conforme a necessidade.

Vector: Outra implementação de List, pode ser visto como uma ArrayList, mas os métodos são sincronizados, ou seja, o acesso simultâneo por diversos processos será coordenado, é também mais lento que o ArrayList quando não há acesso simultâneo.

LinkedList: outra implementação de List, mas também implementa Queue, aceitando itens duplicado e sendo organizada. É similar ao ArrayList e ao Vector, mas fornece alguns métodos adicionais para a inserção, remoção e acesso aos elementos no inicio e no final da lista. Possui melhor performance do que o ArrayList e o Vector quando se trata de inserir, remover e acessar elementos no inicio ou no final da lista, mas se for precisar acessar algum elemento pelo índice, a performance é muito inferior, sendo lento para pesquisas.

Queue: é a fila, semelhante à lista, tendo como padrão o aceite duplicado de elementos, normalmente organizado, normalmente utilizado em itens que a ordem é importante, como uma fila de banco.

PriorityQueue: implementação concreta de Queue e não aceita nulos

Map: Um Map é um tipo de coleção que identifica os elementos por chaves, desta forma aceita itens duplicados com chaves diferentes.

HashMap: implementação concreta de Map, aceita itens duplicados com chaves diferentes, não organizado, ou seja, os elementos são percorridos aleatoriamente, não ordenada e aceita nulos.

HashTables: outra implementação de Map, aceita itens duplicados com chaves diferentes, semelhante ao HashMap mas os métodos são sincronizados.

TreeMap é uma outra implementação concreta de Map, também suporta itens duplicados com indices diferentes, é ordenado.

Implementando Collections básicas

Listagem 5: Segue uma implementação básica de Collections

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class MinhasCollections {
	public static void main(String[] args) {
		List<Integer> minhaLista = new ArrayList<Integer>();
		minhaLista.add(1);
		minhaLista.add(2);
		minhaLista.add(2);

		for (Integer listaElementos : minhaLista) {
			System.out.println(listaElementos);
		}
		Set<Integer> meuSet = new HashSet<Integer>();
		meuSet.add(1);
		meuSet.add(2);
		meuSet.add(3);
		meuSet.add(1);
		Iterator<Integer> iMeuSet = meuSet.iterator();
		while(iMeuSet.hasNext()){
			System.out.println(iMeuSet.next());
		}



	}

}

Conclusão

As Collections possuem ampla utilização em Java, muito utilizadas para os mais diversos fins. Por serem genéricas por padrão, permite a utilização em diversas soluções, segundo Deitel por exemplo "Collection é comumente utilizada como um tipo de parâmetro nos métodos para permitir processamento polimórfico de todos os objetos que implementam a interface Collection". Este artigo apenas apresentou uma introdução sobre a utilização e implementação básica de Collections, há muito mais a ser estudado e a ser compreendido, o Collection possui grandes capacidades, mas é necessário sempre saber a hora de utilizar a Collection correta, como vimos, há Collections ordenadas, não ordenadas, que não suporta itens duplicados etc., e este artigo teve o intuito de apresentar estes pontos sobre as coleções.

Bom estudo e até o próximo artigo.