0% acharam este documento útil (0 voto)
8 visualizações42 páginas

Resumo Collections Java

O documento aborda o conceito de Collections em Java, que são objetos que agrupam múltiplos elementos para armazenamento e manipulação de dados. O Collections Framework é composto por interfaces, implementações e algoritmos, organizados em uma hierarquia que inclui as famílias Collection e Map. A interface Collection é a raiz da hierarquia, definindo operações básicas, enquanto a interface List, que estende Collection, permite a manipulação de coleções ordenadas e com elementos duplicados.

Enviado por

rodrigo
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
8 visualizações42 páginas

Resumo Collections Java

O documento aborda o conceito de Collections em Java, que são objetos que agrupam múltiplos elementos para armazenamento e manipulação de dados. O Collections Framework é composto por interfaces, implementações e algoritmos, organizados em uma hierarquia que inclui as famílias Collection e Map. A interface Collection é a raiz da hierarquia, definindo operações básicas, enquanto a interface List, que estende Collection, permite a manipulação de coleções ordenadas e com elementos duplicados.

Enviado por

rodrigo
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 42

Collections em Java

O que são Collections?


Uma collection (coleção) é simplesmente um objeto que agrupa múltiplos elementos em
uma única unidade. As collections são usadas para armazenar, recuperar, manipular e
comunicar dados agregados. Tipicamente, elas representam itens de dados que formam
um grupo natural, como uma mão de cartas (uma coleção de cartas), um diretório de e-
mails (uma coleção de endereços de e-mail) ou uma lista telefônica (um mapeamento de
nomes para números de telefone).
Componentes do Collections Framework
O Collections Framework consiste em três componentes principais que trabalham em
conjunto:
Interfaces: Estes são tipos de dados abstratos que representam coleções. As interfaces
permitem que as coleções sejam manipuladas independentemente dos detalhes de sua
representação. Em linguagens orientadas a objetos, as interfaces geralmente formam uma
hierarquia. As principais interfaces do framework incluem Collection, Set, List, Queue,
Deque e Map.
Implementações: Estas são as implementações concretas das interfaces de coleção. Em
essência, elas são estruturas de dados reutilizáveis. O framework fornece várias
implementações para cada interface, otimizadas para diferentes cenários de uso. Por
exemplo, ArrayList e LinkedList são duas implementações diferentes da interface List.
Algoritmos: Estes são os métodos que executam computações úteis, como busca e
classificação, em objetos que implementam interfaces de coleção. Os algoritmos são ditos
polimórficos: ou seja, o mesmo método pode ser usado em muitas implementações
diferentes da interface de coleção apropriada. Em essência, os algoritmos são
funcionalidade reutilizável.

Hierarquia das Collections


Compreender a hierarquia das collections é essencial para dominar o framework e
responder corretamente às questões de concurso. A hierarquia é organizada de forma
lógica, com interfaces mais gerais no topo e implementações específicas nas folhas da
árvore.
Estrutura Geral da Hierarquia
A hierarquia do Collections Framework pode ser dividida em duas grandes famílias:
Família Collection: Representa grupos de objetos individuais. Esta família inclui as
interfaces Collection, List, Set e Queue, juntamente com suas sub-interfaces e
implementações.
Família Map: Representa mapeamentos de chaves para valores. A interface Map não
estende Collection, formando uma hierarquia separada, mas é considerada parte do
Collections Framework devido à sua funcionalidade relacionada.
Hierarquia da Interface Collection
Plain Text
Collection (interface)
├── List (interface)
│ ├── ArrayList (classe)
│ ├── LinkedList (classe)
│ ├── Vector (classe)
│ └── Stack (classe)
├── Set (interface)
│ ├── HashSet (classe)
│ ├── LinkedHashSet (classe)
│ └── SortedSet (interface)
│ └── NavigableSet (interface)
│ └── TreeSet (classe)
└── Queue (interface)
├── PriorityQueue (classe)
├── LinkedList (classe)
└── Deque (interface)
├── ArrayDeque (classe)
└── LinkedList (classe)

Hierarquia da Interface Map


Plain Text
Map (interface)
├── HashMap (classe)
├── LinkedHashMap (classe)
├── Hashtable (classe)
│ └── Properties (classe)
├── SortedMap (interface)
│ └── NavigableMap (interface)
│ └── TreeMap (classe)
└── WeakHashMap (classe)

Características das Principais Interfaces


Collection: É a interface raiz da hierarquia de collections. Define as operações básicas que
todas as collections devem suportar, como adicionar, remover, verificar se contém um
elemento, obter o tamanho, etc. Importante notar que Map não estende Collection.
List: Representa uma coleção ordenada (também conhecida como sequência) que pode
conter elementos duplicados. Os elementos podem ser acessados por índice, e a interface
fornece métodos para manipulação baseada em posição.
Set: Representa uma coleção que não pode conter elementos duplicados. Modela a
abstração matemática de conjunto. Algumas implementações mantêm ordem de inserção,
outras mantêm ordem natural dos elementos.
Queue: Representa uma coleção projetada para manter elementos antes do
processamento. Além das operações básicas de Collection, as filas fornecem operações
adicionais de inserção, extração e inspeção.
Map: Representa um mapeamento de chaves para valores. Não pode conter chaves
duplicadas, e cada chave pode mapear para no máximo um valor. Substitui a classe
Dictionary abstrata.
Pontos Importantes para Concursos
Herança vs Implementação: É crucial entender que algumas classes implementam
múltiplas interfaces. Por exemplo, LinkedList implementa tanto List quanto Queue e Deque.
Isso significa que uma LinkedList pode ser usada como lista, fila ou deque.
Interfaces Marcadoras: Algumas interfaces como RandomAccess são interfaces
marcadoras (marker interfaces) que não definem métodos, mas indicam propriedades
especiais das implementações.
Compatibilidade com Versões Anteriores: O framework mantém compatibilidade com
classes legadas como Vector e Hashtable, que foram retrofitadas para implementar as novas
interfaces.
Relacionamentos Especiais: Certas relações na hierarquia são frequentemente testadas
em concursos:
• ArrayList implementa List e RandomAccess
• LinkedList implementa List, Queue e Deque
• HashSet é implementado internamente usando HashMap
• TreeSet implementa NavigableSet, que estende SortedSet

Implicações Práticas da Hierarquia


A hierarquia bem definida permite polimorfismo efetivo. Você pode declarar uma variável
usando uma interface mais geral e atribuir qualquer implementação compatível. Por
exemplo:
Java
Collection<String> col = new ArrayList<>(); // Válido
List<String> list = new LinkedList<>(); // Válido
Set<String> set = new HashSet<>(); // Válido

Esta flexibilidade é fundamental para escrever código maintível e é frequentemente


explorada em questões de concurso que testam o entendimento sobre polimorfismo e
design de APIs.
A compreensão sólida desta hierarquia também é essencial para os tópicos subsequentes
do seu estudo, especialmente quando trabalhar com Streams API, onde você
frequentemente converterá entre diferentes tipos de collections ou aplicará operações que
retornam tipos específicos de collections.
Interface Collection
A interface [Link] é a raiz da hierarquia de coleções em Java. Ela define o
comportamento comum que todas as coleções de elementos devem ter, exceto os Map s. É
uma interface genérica, o que significa que ela pode ser parametrizada para armazenar
elementos de um tipo específico, garantindo segurança de tipo em tempo de compilação.
Métodos Principais da Interface Collection
Os métodos definidos em Collection são operações fundamentais para gerenciar grupos de
objetos. Conhecer esses métodos é crucial para entender como as coleções funcionam e
para responder a questões que envolvem a manipulação básica de dados.
Método Descrição Retorno Exemplo de Uso
Adiciona um
elemento
e à
boolean add(E e) coleção. boolean [Link]("Java");
Retorna
true se a
coleção foi
modificada.
Adiciona
todos os
elementos
boolean da coleção
addAll(Collection<? c à coleção boolean [Link](anotherList);
extends E> c) atual.
Retorna
true se a
coleção foi
modificada.
Remove
void clear() todos os void [Link]();
elementos
da coleção.
Retorna
true se a
boolean coleção boolean [Link]("Java");
contains(Object o) contém o
elemento
o.
Retorna
true se a
boolean coleção
containsAll(Collection<?> contém
todos os boolean [Link](subList);
c) elementos
da coleção
c.
Retorna
true se a
boolean isEmpty() coleção não boolean [Link]();
contém
elementos.
Retorna um
iterador
Iterator<E> iterator() sobre os Iterator<E> Iterator<String> it = [Link]();
elementos
desta
coleção.
Remove uma
única
instância do
elemento
o da
boolean remove(Object coleção,
o) se boolean [Link]("Java");
presente.
Retorna
true se a
coleção foi
modificada.
Remove
todos os
elementos
da coleção
atual que
boolean também
removeAll(Collection<?> estão boolean [Link](elementsToRemove);
c) presentes na
coleção c .
Retorna
true se a
coleção foi
modificada.
Retém
apenas os
elementos
na coleção
atual que
boolean também
retainAll(Collection<?> estão boolean [Link](elementsToKeep);
c) contidos na
coleção c .
Retorna
true se a
coleção foi
modificada.
Retorna o
int size() número de int [Link]();
elementos
na coleção.
Retorna um
array
contendo
Object[] toArray() todos os Object[] Object[] arr = [Link]();
elementos
desta
coleção.
Retorna um
array
contendo
todos os
elementos
desta
<T> T[] toArray(T[] a) coleção; o T[] String[] arr = [Link](new
tipo de String[0]);
tempo de
execução do
array
retornado é
o do array
especificado.
Considerações Importantes para o Concurso
1. Contratos dos Métodos: A FUNDATEC pode explorar o conhecimento sobre o contrato
dos métodos. Por exemplo, add() pode lançar UnsupportedOperationException se a
coleção não suporta a operação, ou NullPointerException se o elemento é nulo e a
coleção não permite nulos. remove() também pode lançar
UnsupportedOperationException .
2. equals() ** e hashCode() :** Os métodos contains() , remove() , containsAll() ,
removeAll() e retainAll() dependem fortemente da implementação correta dos
métodos equals() e hashCode() dos objetos armazenados na coleção. Se esses
métodos não forem sobrescritos corretamente para classes personalizadas, o
comportamento da coleção pode ser inesperado. Questões podem apresentar cenários
onde a falta de implementação adequada desses métodos leva a resultados incorretos.
3. Iteração: O método iterator() é fundamental para percorrer os elementos de uma
coleção. O Iterator permite remover elementos da coleção durante a iteração de forma
segura, o que não é possível com um for-each loop diretamente (lançaria
ConcurrentModificationException se a coleção for modificada por outro meio durante a
iteração).
4. Generics: A utilização de Generics ( <E> ) é um ponto chave. Garante segurança de tipo
em tempo de compilação e evita ClassCastException em tempo de execução. Questões
podem apresentar código sem Generics para testar o entendimento sobre os problemas
que isso pode causar.
5. Operações de Conjunto: removeAll() e retainAll() são operações de conjunto
(diferença e interseção, respectivamente) que podem ser cobradas em cenários
práticos.
Exemplo Básico de Uso da Interface Collection
Java
import [Link];
import [Link];
import [Link];

public class ExemploCollection {


public static void main(String[] args) {
// Usando a interface Collection com uma implementação ArrayList
Collection<String> frutas = new ArrayList<>();

// Adicionando elementos
[Link]("Maçã");
[Link]("Banana");
[Link]("Laranja");
[Link]("Coleção após adicionar: " + frutas); // [Maçã,
Banana, Laranja]

// Verificando o tamanho
[Link]("Tamanho da coleção: " + [Link]()); // 3

// Verificando se contém um elemento


[Link]("Contém 'Banana'? " + [Link]("Banana"));
// true
[Link]("Contém 'Uva'? " + [Link]("Uva")); //
false

// Removendo um elemento
[Link]("Banana");
[Link]("Coleção após remover 'Banana': " + frutas); //
[Maçã, Laranja]

// Iterando sobre a coleção


[Link]("Elementos via Iterator:");
Iterator<String> it = [Link]();
while ([Link]()) {
String fruta = [Link]();
[Link]("- " + fruta);
if ([Link]("Maçã")) {
[Link](); // Remoção segura durante a iteração
}
}
[Link]("Coleção após iteração e remoção: " + frutas); //
[Laranja]

// Verificando se está vazia


[Link]("Coleção está vazia? " + [Link]()); //
false

// Limpando a coleção
[Link]();
[Link]("Coleção após limpar: " + frutas); // []
[Link]("Coleção está vazia? " + [Link]()); //
true
}
}

Dominar a interface Collection é o primeiro passo para entender as interfaces mais


específicas e suas implementações, que serão detalhadas a seguir. A FUNDATEC pode
apresentar questões que exigem a compreensão dos métodos básicos e suas implicações,
especialmente em relação à mutabilidade e à segurança de tipo.

Interface List
A interface [Link] estende Collection e representa uma coleção ordenada de
elementos. Isso significa que os elementos em uma List têm uma ordem específica
(baseada na ordem de inserção ou em alguma outra lógica) e podem ser acessados por seu
índice (posição numérica). Além disso, uma List permite elementos duplicados.
Características Principais da List
• Ordenada: Os elementos são armazenados e recuperados em uma sequência
previsível. A ordem de inserção é geralmente mantida.
• Acesso por Índice: Os elementos podem ser acessados, inseridos ou removidos usando
um índice inteiro (baseado em zero), semelhante a um array.
• Permite Duplicatas: Uma List pode conter múltiplas ocorrências do mesmo
elemento.
Métodos Adicionais da Interface List
Além dos métodos herdados de Collection , a interface List adiciona métodos específicos
para manipulação baseada em índice e outras operações relacionadas à ordem:
Método Descrição Retorno Exemplo de Uso Observ
Insere o
elemento Desloca
void add(int especificado void [Link](1, "C++"); elemen
index, E element) na posição subseq
index na para a d
lista.
Insere todos
os
boolean addAll(int elementos Desloca
index, Collection<? dac coleção
na lista, boolean [Link](0, otherList); elemen
subseq
extends E> c) começando para a d
na posição
index .
Retorna o
elemento na
E get(int index) posição E String s = [Link](0); 
index na
lista.
int indexOf(Object Retorna o int int idx = Usa eq
o) índice da [Link]("Java"); para
primeira compar
ocorrência
do elemento
o na lista,
ou -1 se não
encontrado.
Retorna o
índice da
int última Usa eq
lastIndexOf(Object ocorrência int int idx = para
o) do elemento [Link]("Java"); compar
o na lista,
ou -1 se não
encontrado.
Retorna um Permite
ListIterator iteração
ListIterator<E> sobre os ListIterator<E> ListIterator<String> li = bidirec
listIterator() elementos [Link](); modific
da lista (em da lista
ordem).
Retorna um
ListIterator
ListIterator<E> sobre os
listIterator(int elementos ListIterator<E> ListIterator<String> li = 
index) da lista, [Link]([Link]());
começando
na posição
index .
Remove o Desloca
E remove(int elemento na String removed = elemen
index) posição E [Link](0); subseq
index na para a
lista. esquerd
Substitui o
elemento na Retorna
E set(int index, E posição String old = [Link](0, elemen
element) index na E "Python"); foi
lista pelo substitu
elemento
especificado.
Retorna uma
visão da Alteraçõ
List<E> subList(int porção da
lista entre List<String> sub = sub-list
fromIndex, int fromIndex List<E> [Link](1, 3); refletid
toIndex) (inclusive) e lista ori
toIndex vice-ve
(exclusive).
Principais Implementações da Interface List
As implementações mais comuns de List são ArrayList e LinkedList , cada uma com suas
características de performance e uso ideais.
ArrayList
• Baseado em Array Redimensionável: Internamente, ArrayList usa um array para
armazenar os elementos. Quando o array interno fica cheio, um novo array maior é
criado e os elementos são copiados.
• Acesso Rápido por Índice ( get ): Operações de get(index) são muito rápidas (tempo
constante, O(1)) porque o acesso a elementos em um array é direto.
• Inserção/Remoção Lenta no Meio: Inserir ou remover elementos no meio da lista é
lento (tempo linear, O(n)) porque exige o deslocamento de todos os elementos
subsequentes.
• Adição Rápida no Final: Adicionar elementos no final da lista é geralmente rápido
(tempo constante amortizado, O(1)), mas pode ser lento ocasionalmente se o array
precisar ser redimensionado.
• Melhor para: Cenários onde o acesso aleatório (por índice) é frequente e as
inserções/remoções são mais comuns no final da lista.
LinkedList
• Baseado em Lista Duplamente Encadeada: Internamente, LinkedList armazena os
elementos em nós, onde cada nó contém o elemento e referências para o nó anterior e
o próximo nó.
• Acesso Lento por Índice ( get ): Acesso a elementos por índice é lento (tempo linear,
O(n)) porque exige percorrer a lista do início ou do fim até o índice desejado.
• Inserção/Remoção Rápida em Qualquer Posição: Inserir ou remover elementos em
qualquer posição é rápido (tempo constante, O(1)) uma vez que o nó é encontrado. O
tempo para encontrar o nó ainda é O(n).
• Melhor para: Cenários onde inserções e remoções no início ou no meio da lista são
frequentes, e o acesso por índice é menos comum.
• Implementa Deque : LinkedList também implementa a interface Deque (Double
Ended Queue), o que a torna útil para operações de fila e pilha (como addFirst ,
removeLast , etc.).
Vector e Stack (Legadas)
• Vector ****: Similar a ArrayList , mas é sincronizado (thread-safe). Isso o torna mais
lento em ambientes de thread única. É uma classe legada e geralmente ArrayList é
preferível, a menos que a sincronização explícita seja necessária (e mesmo assim,
[Link]() é geralmente uma opção melhor).
• Stack ****: Estende Vector e implementa uma estrutura de dados LIFO (Last-In, First-
Out). Possui métodos como push() , pop() , peek() . Também é legada e ArrayDeque é
a implementação preferida para pilhas e filas.
Considerações para o Concurso FUNDATEC
1. Escolha da Implementação: Questões da FUNDATEC podem apresentar um cenário e
pedir a List mais adequada. Entender as diferenças de performance entre ArrayList e
LinkedList é crucial. Por exemplo, para um log de eventos onde novos eventos são
sempre adicionados ao final e raramente acessados por índice, ArrayList seria uma boa
escolha. Para uma lista de tarefas onde tarefas são frequentemente adicionadas e
removidas do início ou meio, LinkedList pode ser mais eficiente.
2. ListIterator ****: Este iterador é mais poderoso que o Iterator básico, permitindo
iteração bidirecional e modificação da lista durante a iteração. Pode ser um ponto de
detalhe em questões mais aprofundadas.
3. subList() ****: A natureza de 'visão' da subList é um ponto importante. Modificações
na sub-lista afetam a lista original e vice-versa. Isso pode ser fonte de pegadinhas em
questões.
4. equals() ** e hashCode() em List :** A interface List adiciona um contrato específico
para equals() e hashCode() : duas listas são consideradas iguais se contêm os mesmos
elementos na mesma ordem. Isso é diferente de Set , onde a ordem não importa.
5. Classes Legadas: Embora Vector e Stack sejam legadas, a FUNDATEC pode incluí-las
em questões para testar o conhecimento sobre suas características (sincronização,
LIFO) e a preferência por alternativas modernas ( ArrayList , ArrayDeque ).
Exemplo de Uso da Interface List
Java
import [Link];
import [Link];
import [Link];

public class ExemploList {


public static void main(String[] args) {
// Usando ArrayList
List<String> nomesArrayList = new ArrayList<>();
[Link]("Alice");
[Link]("Bob");
[Link]("Charlie");
[Link]("ArrayList: " + nomesArrayList); // [Alice, Bob,
Charlie]

// Acessando por índice


[Link]("Elemento no índice 1 (ArrayList): " +
[Link](1)); // Bob

// Inserindo no meio
[Link](1, "David");
[Link]("ArrayList após inserção: " + nomesArrayList); //
[Alice, David, Bob, Charlie]

// Removendo por índice


String removido = [Link](2); // Remove Bob
[Link]("ArrayList após remoção: " + nomesArrayList + ",
Removido: " + removido); // [Alice, David, Charlie], Removido: Bob

// Usando LinkedList
List<String> nomesLinkedList = new LinkedList<>();
[Link]("Xavier");
[Link]("Yara");
[Link]("Zoe");
[Link]("LinkedList: " + nomesLinkedList); // [Xavier,
Yara, Zoe]

// LinkedList como Deque (exemplo)


((LinkedList<String>) nomesLinkedList).addFirst("Walter");
[Link]("LinkedList após addFirst: " + nomesLinkedList);
// [Walter, Xavier, Yara, Zoe]
}
}

O domínio da interface List e suas implementações é crucial, pois ela é uma das coleções
mais utilizadas no desenvolvimento Java. A FUNDATEC frequentemente testa a capacidade
do candidato de escolher a implementação correta para um dado problema e de entender
as implicações de performance de cada escolha.

Interface Set
A interface [Link] estende Collection e representa uma coleção que não contém
elementos duplicados. Ela modela a abstração matemática de um conjunto. A principal
característica de um Set é que cada elemento é único; se você tentar adicionar um
elemento que já existe no conjunto, a operação de adição não terá efeito e o método add()
retornará false .
Características Principais da Set
• Não Permite Duplicatas: Garante que todos os elementos armazenados no conjunto
são únicos. A unicidade é determinada pelo método equals() dos elementos.
• Não Ordenada (Geralmente): A maioria das implementações de Set não garante uma
ordem específica para os elementos. A ordem de iteração pode não ser a ordem de
inserção, nem uma ordem natural.
• Acesso por Elemento: Não há acesso por índice, pois a ordem não é garantida.
Métodos da Interface Set
A interface Set não adiciona nenhum método novo além dos herdados de Collection . No
entanto, o comportamento dos métodos herdados é modificado para refletir a restrição de
unicidade. Por exemplo, o método add(E e) retorna false se o elemento já estiver presente
no conjunto.
Principais Implementações da Interface Set
As implementações mais comuns de Set são HashSet , LinkedHashSet e TreeSet , cada
uma com suas propriedades específicas de performance e ordenação.
HashSet
• Baseado em Tabela Hash: Internamente, HashSet utiliza um HashMap para
armazenar seus elementos. Cada elemento adicionado ao HashSet é armazenado
como uma chave no HashMap , e um objeto Object dummy é usado como valor.
• Não Garante Ordem: A ordem dos elementos em um HashSet não é garantida e pode
mudar ao longo do tempo, especialmente após adições ou remoções.
• Performance: Oferece performance de tempo constante (O(1)) para operações básicas
como add() , remove() , contains() e size() , assumindo que a função de hash distribui
os elementos uniformemente. Esta é a implementação de Set mais rápida para
operações gerais.
• Requer hashCode() e equals() : Para que HashSet funcione corretamente e garanta a
unicidade dos elementos, a classe dos objetos armazenados deve sobrescrever
corretamente os métodos hashCode() e equals() . Se esses métodos não forem
implementados corretamente, HashSet pode falhar em identificar duplicatas.
LinkedHashSet
• Mantém Ordem de Inserção: LinkedHashSet é uma subclasse de HashSet que
mantém uma lista duplamente encadeada de todos os seus elementos. Isso garante
que a ordem de iteração seja a ordem em que os elementos foram inseridos no
conjunto.
• Performance: A performance das operações básicas é ligeiramente inferior à de
HashSet devido à sobrecarga de manter a lista encadeada, mas ainda é geralmente
O(1).
• Uso: Útil quando a ordem de inserção é importante, mas a unicidade dos elementos
também é necessária.
TreeSet
• Baseado em Árvore Binária de Busca Balanceada (Red-Black Tree): Internamente,
TreeSet utiliza um TreeMap para armazenar seus elementos. Os elementos são
armazenados em ordem natural (se implementarem Comparable ) ou de acordo com
um Comparator fornecido no momento da criação do TreeSet .
• Elementos Ordenados: Os elementos são armazenados em ordem crescente (natural
ou definida por Comparator ). Isso significa que a iteração sobre um TreeSet sempre
retornará os elementos em ordem ordenada.
• Performance: As operações básicas como add() , remove() e contains() têm
performance de tempo logarítmico (O(log n)), o que é mais lento que HashSet mas
mais rápido que List para grandes conjuntos de dados quando a ordem é necessária.
• Requer Comparable ou Comparator : Os elementos armazenados em um TreeSet
devem ser comparáveis. Isso significa que eles devem implementar a interface
Comparable ou um Comparator deve ser fornecido ao TreeSet no momento da sua
criação. Se os elementos não forem comparáveis, uma ClassCastException será lançada.
• Implementa SortedSet e NavigableSet : TreeSet implementa SortedSet (que
adiciona métodos para obter o primeiro/último elemento, subconjuntos, etc.) e
NavigableSet (que adiciona métodos para navegação mais granular, como lower() ,
floor() , ceiling() , higher() ).

Considerações para o Concurso FUNDATEC


1. Unicidade e equals() / hashCode() : A FUNDATEC pode apresentar questões que
testam a compreensão da unicidade em Set e a importância dos métodos equals() e
hashCode() . Cenários onde esses métodos não são sobrescritos corretamente para
classes personalizadas são comuns em questões de pegadinha.
2. Escolha da Implementação: Saber quando usar HashSet (performance, sem ordem),
LinkedHashSet (performance, ordem de inserção) ou TreeSet (ordenado, performance
logarítmica) é fundamental. Por exemplo, para remover duplicatas de uma lista sem se
preocupar com a ordem, HashSet é a melhor escolha. Para manter a ordem de
inserção enquanto garante unicidade, LinkedHashSet . Para ter elementos sempre
ordenados, TreeSet .
3. Comparable ** e Comparator :** A necessidade de Comparable ou Comparator para
TreeSet é um ponto frequentemente cobrado. Entender a diferença entre eles e como
implementá-los é importante.
4. Operações de Conjunto: Set é ideal para operações matemáticas de conjunto como
união ( addAll ), interseção ( retainAll ) e diferença ( removeAll ). Questões podem
envolver a aplicação dessas operações.
Exemplo de Uso da Interface Set
Java
import [Link];
import [Link];
import [Link];
import [Link];

public class ExemploSet {


public static void main(String[] args) {
// Usando HashSet (sem ordem garantida)
Set<String> hashSet = new HashSet<>();
[Link]("Maçã");
[Link]("Banana");
[Link]("Laranja");
[Link]("Maçã"); // Tentando adicionar duplicata
[Link]("HashSet: " + hashSet); // Ordem pode variar, Maçã
aparece uma vez
[Link]("Adicionou Maçã novamente? " +
[Link]("Maçã")); // false
// Usando LinkedHashSet (mantém ordem de inserção)
Set<String> linkedHashSet = new LinkedHashSet<>();
[Link]("Maçã");
[Link]("Banana");
[Link]("Laranja");
[Link]("Maçã");
[Link]("LinkedHashSet: " + linkedHashSet); // [Maçã,
Banana, Laranja]

// Usando TreeSet (elementos ordenados naturalmente)


Set<String> treeSet = new TreeSet<>();
[Link]("Maçã");
[Link]("Banana");
[Link]("Laranja");
[Link]("Maçã");
[Link]("TreeSet: " + treeSet); // [Banana, Laranja, Maçã]
(ordenado alfabeticamente)

// Exemplo de remoção
[Link]("Banana");
[Link]("HashSet após remover Banana: " + hashSet);

// Exemplo de contains
[Link]("HashSet contém Laranja? " +
[Link]("Laranja")); // true
}
}

O conhecimento aprofundado da interface Set e suas implementações é vital para o


concurso, especialmente no que diz respeito à garantia de unicidade e às implicações de
performance e ordenação de cada tipo de conjunto. A FUNDATEC pode apresentar cenários
onde a escolha da implementação correta de Set é crucial para a eficiência ou correção do
código.

Interface Map
A interface [Link] é uma parte fundamental do Java Collections Framework, mas,
diferentemente de List , Set e Queue , ela não estende a interface **** Collection . Um
Map representa um mapeamento de chaves para valores, onde cada chave é única e
mapeia para no máximo um valor. É ideal para armazenar pares de dados onde você precisa
recuperar um valor rapidamente usando uma chave específica.
Características Principais da Map
• Pares Chave-Valor: Armazena dados como pares de chave e valor ( key-value pairs ).
• Chaves Únicas: Cada chave em um Map deve ser única. Se você tentar adicionar um
par com uma chave já existente, o valor associado a essa chave será atualizado.
• Valores Duplicados Permitidos: Diferentemente das chaves, os valores podem ser
duplicados.
• Não Ordenada (Geralmente): A maioria das implementações de Map não garante
uma ordem específica para as chaves ou valores.
Métodos Principais da Interface Map
Método Descrição Retorno Exemplo de Uso
Associa o
valor
especificado à
chave
especificada
V put(K key, V value) neste mapa. V (valor [Link]("Brasil", "Brasília");
Se o mapa já anterior)
continha um
mapeamento
para a chave,
o valor antigo
é substituído.
V get(Object key) Retorna o V String capital =
valor ao qual [Link]("Brasil");
a chave
especificada
está
mapeada, ou
null se este
mapa não
contém
mapeamento
para a chave.
Remove o
mapeamento
V remove(Object para a chave V (valor String removed =
key) especificada removido) [Link]("Brasil");
deste mapa,
se presente.
Retorna true
boolean se este mapa
containsKey(Object contém um
key) mapeamento boolean [Link]("Brasil");
para a chave
especificada.
Retorna true
se este mapa
boolean mapeia uma
containsValue(Object ou mais boolean [Link]("Brasília");
value) chaves para o
valor
especificado.
Retorna o
número de
int size() mapeamentos int [Link]();
chave-valor
neste mapa.
Retorna true
se este mapa
boolean isEmpty() não contém boolean [Link]();
mapeamentos
chave-valor.
void putAll(Map<? Copia todos void [Link](otherMap);
extends K, ? extends os
V> m) mapeamentos
do mapa
especificado
para este
mapa.
Remove todos
void clear() os
mapeamentos void [Link]();
deste mapa.
Retorna um
Set de todas Set<String> chaves =
Set<K> keySet() as chaves Set<K> [Link]();
contidas
neste mapa.
Retorna uma
Collection de
Collection<V> todos os Collection<V> Collection<String> valores =
values() valores [Link]();
contidos
neste mapa.
Retorna um
Set de
Set<[Link]<K, objetos Set<[Link]<K, Set<[Link]<String, String>>
V>> entrySet() [Link] V>> entradas = [Link]();
contidos
neste mapa.
Principais Implementações da Interface Map
As implementações mais comuns de Map são HashMap , LinkedHashMap e TreeMap , cada
uma com suas características de performance e ordenação.
HashMap
• Baseado em Tabela Hash: Internamente, HashMap utiliza uma tabela hash para
armazenar os pares chave-valor. É a implementação de Map mais utilizada e
geralmente a mais rápida.
• Não Garante Ordem: A ordem dos elementos em um HashMap não é garantida e pode
mudar ao longo do tempo. Não há garantia de que a ordem de iteração será a ordem de
inserção ou qualquer outra ordem específica.
• Performance: Oferece performance de tempo constante (O(1)) para operações básicas
como put() , get() , remove() , containsKey() e size() , assumindo que a função de
hash distribui as chaves uniformemente. Esta é a implementação de Map mais rápida
para operações gerais.
• Requer hashCode() e equals() : Para que HashMap funcione corretamente e garanta a
unicidade das chaves, a classe das chaves deve sobrescrever corretamente os métodos
hashCode() e equals() . Se esses métodos não forem implementados corretamente,
HashMap pode falhar em identificar chaves duplicadas ou em recuperar valores
associados a chaves existentes.
• Permite uma chave null e múltiplos valores null : HashMap permite uma única
chave null e múltiplos valores null .
LinkedHashMap
• Mantém Ordem de Inserção: LinkedHashMap é uma subclasse de HashMap que
mantém uma lista duplamente encadeada de todos os seus elementos. Isso garante
que a ordem de iteração seja a ordem em que os pares chave-valor foram inseridos no
mapa.
• Performance: A performance das operações básicas é ligeiramente inferior à de
HashMap devido à sobrecarga de manter a lista encadeada, mas ainda é geralmente
O(1).
• Uso: Útil quando a ordem de inserção é importante, mas a performance de um
HashMap é desejada.
TreeMap
• Baseado em Árvore Binária de Busca Balanceada (Red-Black Tree): Internamente,
TreeMap utiliza uma árvore binária de busca balanceada para armazenar os pares
chave-valor. As chaves são armazenadas em ordem natural (se implementarem
Comparable ) ou de acordo com um Comparator fornecido no momento da criação do
TreeMap .
• Chaves Ordenadas: As chaves são armazenadas em ordem crescente (natural ou
definida por Comparator ). Isso significa que a iteração sobre um TreeMap sempre
retornará as chaves em ordem ordenada.
• Performance: As operações básicas como put() , get() , remove() e containsKey() têm
performance de tempo logarítmico (O(log n)), o que é mais lento que HashMap mas
mais rápido que List para grandes conjuntos de dados quando a ordem das chaves é
necessária.
• Requer Comparable ou Comparator : As chaves armazenadas em um TreeMap devem
ser comparáveis. Isso significa que elas devem implementar a interface Comparable ou
um Comparator deve ser fornecido ao TreeMap no momento da sua criação. Se as
chaves não forem comparáveis, uma ClassCastException será lançada.
• Não permite chaves null : TreeMap não permite chaves null .
• Implementa SortedMap e NavigableMap : TreeMap implementa SortedMap (que
adiciona métodos para obter a primeira/última chave, sub-mapas, etc.) e NavigableMap
(que adiciona métodos para navegação mais granular, como lowerKey() , floorKey() ,
ceilingKey() , higherKey() ).
Hashtable (Legada)
• Sincronizada: Similar a HashMap , mas é sincronizada (thread-safe). Isso a torna mais
lenta em ambientes de thread única. É uma classe legada e geralmente
ConcurrentHashMap ou [Link]() são preferíveis para uso em
ambientes multi-thread.
• Não permite chaves ou valores null : Lança NullPointerException se tentar adicionar
uma chave ou valor null .
Considerações para o Concurso FUNDATEC
1. Distinção Map vs Collection : A FUNDATEC pode tentar confundir o candidato sobre o
fato de Map não estender Collection . É importante reforçar que Map é uma estrutura
de dados de pares chave-valor, enquanto Collection é para grupos de elementos
únicos.
2. Unicidade de Chaves e equals() / hashCode() : Assim como em HashSet , a correta
implementação de equals() e hashCode() para as classes usadas como chaves é vital
para o funcionamento correto de HashMap e LinkedHashMap . Questões podem
explorar cenários onde essa regra é violada.
3. Escolha da Implementação: Saber quando usar HashMap (performance, sem ordem),
LinkedHashMap (performance, ordem de inserção) ou TreeMap (chaves ordenadas,
performance logarítmica) é um ponto chave. Por exemplo, para um cache simples,
HashMap é ideal. Para um mapa onde a ordem de inserção é importante (ex: histórico
de acesso), LinkedHashMap . Para um dicionário onde as chaves precisam estar sempre
ordenadas (ex: índice remissivo), TreeMap .
4. Iteração sobre Map : As três formas de iterar sobre um Map ( keySet() , values() ,
entrySet() ) são importantes. entrySet() é geralmente a mais eficiente para iterar sobre
chaves e valores simultaneamente.
5. null ** em HashMap vs TreeMap / Hashtable :** A capacidade de HashMap de
aceitar uma chave null e valores null é um detalhe que pode ser cobrado,
contrastando com TreeMap e Hashtable que não permitem chaves null .
Exemplo de Uso da Interface Map
Java
import [Link];
import [Link];
import [Link];
import [Link];

public class ExemploMap {


public static void main(String[] args) {
// Usando HashMap (sem ordem garantida)
Map<String, String> capitaisHashMap = new HashMap<>();
[Link]("Brasil", "Brasília");
[Link]("Argentina", "Buenos Aires");
[Link]("Chile", "Santiago");
[Link]("HashMap: " + capitaisHashMap); // Ordem pode
variar

// Acessando valor
[Link]("Capital do Brasil: " +
[Link]("Brasil")); // Brasília

// Atualizando valor
[Link]("Brasil", "Nova Brasília");
[Link]("HashMap após atualização: " + capitaisHashMap);
// {Brasil=Nova Brasília, ...}

// Usando LinkedHashMap (mantém ordem de inserção)


Map<String, String> capitaisLinkedHashMap = new LinkedHashMap<>();
[Link]("Brasil", "Brasília");
[Link]("Argentina", "Buenos Aires");
[Link]("Chile", "Santiago");
[Link]("LinkedHashMap: " + capitaisLinkedHashMap); //
{Brasil=Brasília, Argentina=Buenos Aires, Chile=Santiago}

// Usando TreeMap (chaves ordenadas naturalmente)


Map<String, String> capitaisTreeMap = new TreeMap<>();
[Link]("Brasil", "Brasília");
[Link]("Argentina", "Buenos Aires");
[Link]("Chile", "Santiago");
[Link]("TreeMap: " + capitaisTreeMap); //
{Argentina=Buenos Aires, Brasil=Brasília, Chile=Santiago}

// Iterando sobre um Map usando entrySet()


[Link]("\nIterando sobre HashMap com entrySet():");
for ([Link]<String, String> entrada : [Link]())
{
[Link]("Chave: " + [Link]() + ", Valor: " +
[Link]());
}
}
}

O domínio da interface Map e suas implementações é tão importante quanto o das


interfaces Collection para o concurso. A FUNDATEC frequentemente inclui questões que
exigem a escolha da implementação de Map mais adequada para um problema específico,
considerando performance, ordenação e comportamento em relação a chaves e valores
nulos.
Comparação de Performance
A escolha da implementação correta de uma interface de Collection ou Map é crucial para a
performance de uma aplicação Java. A FUNDATEC, em suas questões, pode apresentar
cenários onde a eficiência é o fator determinante para a escolha da estrutura de dados.
Compreender as complexidades de tempo (Big O Notation) das operações mais comuns é
fundamental.
Complexidade de Tempo das Operações Comuns
A tabela abaixo resume a complexidade de tempo das operações básicas para as
implementações mais comuns. n representa o número de elementos na coleção.
Operação ArrayList LinkedList HashSet LinkedHashSet Tre
O(1) O(1) O(1)
add(element) amortizado O(1) amortizado amortizado O(lo
add(index, O(n) O(1) N/A N/A N/A
element)
get(index) O(1) O(n) N/A N/A N/A
remove(element) O(n) O(n) O(1) O(1) O(lo
amortizado amortizado
remove(index) O(n) O(1) N/A N/A N/A
contains(element) O(n) O(n) O(1) O(1) O(lo
amortizado amortizado
size() O(1) O(1) O(1) O(1) O(1
Iteração O(n) O(n) O(n) O(n) O(n
Observações sobre a Tabela:
• O(1) amortizado: Significa que a operação leva tempo constante na maioria das vezes,
mas ocasionalmente pode levar mais tempo (por exemplo, quando um ArrayList
precisa ser redimensionado ou um HashMap precisa ser re-hashed).
• O(n): Tempo linear, o tempo de execução cresce proporcionalmente ao número de
elementos.
• O(log n): Tempo logarítmico, o tempo de execução cresce muito lentamente com o
número de elementos (típico de estruturas baseadas em árvore).
• N/A: Não aplicável, a operação não existe para essa interface/implementação.
Fatores que Afetam a Performance
Além da complexidade de tempo teórica, outros fatores práticos influenciam a
performance:
1. Fator de Carga (Load Factor) e Capacidade Inicial de HashMap / HashSet :
• O load factor (fator de carga) padrão é 0.75. Quando o número de elementos excede
capacidade * load factor , a tabela hash é redimensionada (re-hashed), o que é uma
operação cara (O(n)).
• Definir uma initial capacity (capacidade inicial) adequada para HashMap e HashSet
pode evitar re-hashing frequente, melhorando a performance, especialmente ao
adicionar muitos elementos de uma vez.
1. Implementação de hashCode() e equals() :
• Uma má implementação de hashCode() (que gera muitos colisões) pode degradar a
performance de HashSet e HashMap de O(1) para O(n) no pior caso.
• É crucial que equals() e hashCode() sejam consistentes: se dois objetos são equals() ,
seus hashCode() devem ser iguais.
1. Uso de Comparable e Comparator em TreeSet / TreeMap :
• A performance de TreeSet e TreeMap depende da eficiência da comparação dos
elementos/chaves. Comparações complexas podem impactar o tempo de execução.
1. Sincronização:
• Classes legadas como Vector e Hashtable são sincronizadas, o que as torna thread-
safe, mas introduz uma sobrecarga de performance significativa em ambientes de
thread única ou quando a sincronização não é necessária.
• Para thread-safety, é geralmente preferível usar ConcurrentHashMap ou as versões
sincronizadas fornecidas por [Link]() , [Link]() ,
etc., que oferecem controle mais granular ou são otimizadas para concorrência.
Dicas para o Concurso
• Análise de Cenários: A FUNDATEC frequentemente apresenta um problema e pede a
melhor estrutura de dados. Analise o problema em termos de:
• Necessidade de Ordem: Se a ordem de inserção ou uma ordem natural/definida é
crucial.
• Permissão de Duplicatas: Se elementos repetidos são permitidos ou não.
• Frequência de Operações: Quais operações ( add , get , remove , contains ) serão
mais frequentes e em que posições (início, meio, fim).
• Uso de Chaves/Valores: Se a estrutura é um mapeamento ou uma coleção simples.
• ArrayList ** vs LinkedList :**
• Use ArrayList quando precisar de acesso rápido por índice ( get ) e a maioria das
adições/remoções for no final da lista.
• Use LinkedList quando precisar de inserções/remoções rápidas no início ou meio da
lista, e o acesso por índice for menos frequente.
• HashSet ** vs TreeSet vs LinkedHashSet :**
• Use HashSet para a performance mais rápida e quando a ordem não importa.
• Use LinkedHashSet quando a ordem de inserção precisa ser mantida.
• Use TreeSet quando os elementos precisam ser mantidos em ordem natural ou
definida por um Comparator .
• HashMap ** vs TreeMap vs LinkedHashMap :**
• Use HashMap para a performance mais rápida e quando a ordem das chaves não
importa.
• Use LinkedHashMap quando a ordem de inserção das chaves precisa ser mantida.
• Use TreeMap quando as chaves precisam ser mantidas em ordem natural ou
definida por um Comparator .
Dominar a comparação de performance e saber quando aplicar cada estrutura de dados é
um diferencial importante para o concurso da PROCERGS, pois demonstra não apenas
conhecimento teórico, mas também a capacidade de tomar decisões de design eficientes.

Dicas Específicas para a Banca FUNDATEC


A banca FUNDATEC é conhecida por elaborar questões que testam não apenas o
conhecimento teórico, mas também a capacidade do candidato de aplicar conceitos em
cenários práticos e identificar detalhes importantes da linguagem Java. Para o tópico de
Collections, preste atenção aos seguintes pontos:
1. Compreensão Profunda das Interfaces vs. Implementações:
• A FUNDATEC pode apresentar um trecho de código que declara uma variável com o tipo
de uma interface ( List , Set , Map ) e a inicializa com uma implementação específica
( ArrayList , HashSet , HashMap ). Questões podem perguntar sobre o comportamento
do código, que dependerá da implementação concreta.
• Exemplo: List<String> lista = new LinkedList<>(); e depois perguntar sobre a performance
de [Link](index) . A resposta deve considerar a performance de LinkedList para get() ,
que é O(n).
1. equals() ** e hashCode() :**
• Este é um ponto recorrente em questões de Collections, especialmente para HashSet e
HashMap . A banca pode apresentar uma classe personalizada sem a sobrescrita
correta de equals() e hashCode() e perguntar o que acontece ao adicionar objetos
dessa classe a um Set ou usá-los como chaves em um Map .
• Lembre-se do contrato: se dois objetos são equals() , seus hashCode() devem ser
iguais. O inverso não é verdadeiro (colisões de hash são permitidas, mas devem ser
minimizadas).
1. Mutabilidade e ConcurrentModificationException :
• Modificar uma coleção enquanto ela está sendo iterada (usando um for-each loop ou
Iterator de forma incorreta) pode levar a uma ConcurrentModificationException . A
FUNDATEC pode incluir cenários onde essa exceção é lançada.
• A forma segura de remover elementos durante a iteração é usando o método remove()
do Iterator .
1. Classes Legadas ( Vector , Hashtable , Stack ):
• Embora não sejam as implementações mais recomendadas atualmente, a FUNDATEC
pode incluir questões sobre elas para testar o conhecimento sobre suas características
(principalmente a sincronização e o fato de serem legadas) e a preferência por
alternativas modernas ( ArrayList , HashMap , ArrayDeque ).
1. Nulls em Collections e Maps:
• Entenda quais implementações permitem ou não elementos/chaves/valores null . Por
exemplo, HashMap permite uma chave null e múltiplos valores null , enquanto
TreeMap e Hashtable não permitem chaves null .
1. Operações de Conjunto ( Set ):
• Questões podem envolver a aplicação de operações de conjunto como união ( addAll ),
interseção ( retainAll ) e diferença ( removeAll ) com Set s.
1. Sintaxe e Erros Comuns:
• A banca pode apresentar trechos de código com pequenos erros de sintaxe ou lógica
para que o candidato os identifique. Preste atenção a detalhes como o uso de Generics,
tipos de retorno de métodos e a forma correta de chamar as operações.
1. Cenários de Uso:
• A FUNDATEC gosta de apresentar problemas do mundo real e pedir a melhor estrutura
de dados para resolvê-los. Por exemplo, "Qual a melhor estrutura para armazenar
registros de alunos onde cada aluno tem um ID único e você precisa acessá-los
rapidamente pelo ID?" (Resposta: HashMap<Integer, Aluno> ).
1. Imutabilidade ([Link]...):
• Embora menos comum, a banca pode tocar no conceito de coleções imutáveis ou
wrappers de coleções ( [Link]() , [Link]() , etc.) para
testar a segurança e o design de APIs.
Ao estudar, não se limite a memorizar definições. Tente entender o porquê de cada
característica e quando usar cada tipo de coleção. Pratique com questões de concursos
anteriores da FUNDATEC para se familiarizar com o estilo da banca.

Preparação para Tópicos Subsequentes: Interfaces


Funcionais, Lambdas, Method Reference, Programação
Funcional e Stream API
O Java Collections Framework é a base sobre a qual muitas das funcionalidades modernas
do Java 8+ foram construídas, especialmente no que diz respeito à Programação Funcional
e à Stream API. Compreender bem as Collections é um pré-requisito fundamental para
dominar esses tópicos avançados, que são cada vez mais cobrados em concursos.
Interfaces Funcionais e Expressões Lambda com Collections
Interfaces Funcionais são interfaces com um único método abstrato (SAM - Single Abstract
Method). Elas são o alvo das Expressões Lambda e Method References. Muitas interfaces do
Collections Framework, ou interfaces que interagem com Collections, foram aprimoradas
ou introduzidas no Java 8 para serem Interfaces Funcionais, permitindo o uso de Lambdas.
• Comparator<T> ****: Uma das interfaces funcionais mais importantes para Collections.
Usada para definir uma ordem de classificação para elementos em TreeSet , TreeMap
ou para classificar List s usando [Link]() ou [Link]() . Antes do Java 8, exigia
uma classe anônima; agora, pode ser implementada com uma Lambda:
• Predicate<T> ****: Usada para filtrar elementos. O método removeIf() (introduzido na
interface Collection no Java 8) aceita um Predicate para remover elementos que
satisfazem uma condição:
• Consumer<T> ****: Usada para realizar uma ação em cada elemento. O método
forEach() (introduzido na interface Iterable , que Collection estende) aceita um
Consumer :

Stream API e Collections


A Stream API, introduzida no Java 8, fornece uma maneira poderosa e funcional de
processar coleções de dados. Streams não são estruturas de dados; eles são uma sequência
de elementos que suportam operações sequenciais e paralelas. A ponte entre Collections e
Streams é feita principalmente pelo método stream() (e parallelStream() ) disponível na
interface Collection .
• Obtendo um Stream de uma Collection:
• Operações Intermediárias (Lazy): Operações como filter() , map() , sorted() ,
distinct() retornam um novo Stream e são executadas de forma lazy (somente quando
uma operação terminal é invocada). Elas permitem transformar e filtrar os dados da
coleção sem modificar a coleção original.
• Operações Terminais (Eager): Operações como forEach() , collect() , reduce() ,
count() , min() , max() , sum() , average() produzem um resultado ou um efeito
colateral e encerram o Stream. Após uma operação terminal, o Stream não pode ser
reutilizado.
Programação Funcional e Imutabilidade
A Stream API promove um estilo de programação mais funcional, onde a imutabilidade é
valorizada. As operações de Stream não modificam a coleção original; elas produzem novos
resultados. Isso contrasta com as operações tradicionais de Collections que
frequentemente modificam a coleção in-place.
Conexão com o Concurso
Para o concurso da PROCERGS, a FUNDATEC pode apresentar questões que combinam o
conhecimento de Collections com as novas funcionalidades do Java 8+:
• Refatoração de Código: Um trecho de código tradicional usando loops para processar
uma coleção pode ser apresentado, e a questão pode pedir a versão refatorada usando
Streams e Lambdas.
• Análise de Saída: Dado um código que usa Streams e Lambdas em Collections, o
candidato deve prever a saída.
• Escolha da Melhor Abordagem: Cenários onde o uso de Streams pode simplificar o
código ou melhorar a performance (especialmente com parallelStream() ).
• Conhecimento de Collectors : A classe [Link] é fundamental para
transformar Streams de volta em Collections ou para agrupar/sumarizar dados.
Métodos como toList() , toSet() , toMap() , groupingBy() são frequentemente cobrados.
Ao estudar Collections, tenha em mente como cada tipo de coleção se comporta quando
convertida para um Stream e como as operações de Stream podem ser aplicadas para
manipular os dados de forma eficiente e concisa. Isso não só reforçará seu conhecimento
em Collections, mas também construirá uma base sólida para os próximos tópicos do seu
estudo. A FUNDATEC valoriza candidatos que demonstram conhecimento das práticas
modernas de desenvolvimento Java.

Exemplos de Código Importantes


Para solidificar o entendimento e preparar-se para questões práticas, é fundamental revisar
exemplos de código que demonstrem o uso correto e as nuances das Collections. Estes
exemplos cobrem cenários comuns e pontos que a FUNDATEC pode explorar.
1. Removendo Duplicatas de uma Lista
Uma forma eficiente de remover duplicatas de uma List é convertê-la para um Set e
depois de volta para uma List . HashSet é a escolha mais comum para isso devido à sua
performance.
Java
import [Link];
import [Link];
import [Link];
import [Link];

public class RemoverDuplicatas {


public static void main(String[] args) {
List<String> comDuplicatas = new ArrayList<>();
[Link]("Java");
[Link]("Python");
[Link]("Java");
[Link]("C++");
[Link]("Python");

[Link]("Lista com duplicatas: " + comDuplicatas);

// Usando HashSet para remover duplicatas


Set<String> semDuplicatasSet = new HashSet<>(comDuplicatas);
List<String> semDuplicatasList = new ArrayList<>(semDuplicatasSet);

[Link]("Lista sem duplicatas (HashSet): " +


semDuplicatasList);

// Se a ordem de inserção for importante, use LinkedHashSet


Set<String> semDuplicatasLinkedHashSet = new LinkedHashSet<>
(comDuplicatas);
List<String> semDuplicatasLinkedList = new ArrayList<>
(semDuplicatasLinkedHashSet);
[Link]("Lista sem duplicatas (LinkedHashSet, ordem
preservada): " + semDuplicatasLinkedList);
}
}

2. Contando Frequência de Palavras com Map


HashMap é excelente para contar a frequência de ocorrências de elementos, como palavras
em um texto.
Java
import [Link];
import [Link];

public class ContarFrequenciaPalavras {


public static void main(String[] args) {
String texto = "Java é uma linguagem de programação. Java é muito
usada.";
String[] palavras = [Link]().replaceAll("[.,]",
"").split("\\s+");

Map<String, Integer> frequencia = new HashMap<>();

for (String palavra : palavras) {


[Link](palavra, [Link](palavra, 0) + 1);
}

[Link]("Frequência de palavras: " + frequencia);


// Saída esperada (ordem pode variar): {linguagem=1, de=1, muito=1,
programação=1, é=2, java=2, uma=1, usada=1}
}
}

3. Ordenando uma Lista de Objetos Personalizados


Para ordenar objetos personalizados, você pode usar Comparable (para ordem natural) ou
Comparator (para ordem personalizada).
Usando Comparable
Java
import [Link];
import [Link];
import [Link];

class Pessoa implements Comparable<Pessoa> {


String nome;
int idade;

public Pessoa(String nome, int idade) {


[Link] = nome;
[Link] = idade;
}

@Override
public String toString() {
return nome + " (" + idade + ")";
}

// Define a ordem natural: por idade, depois por nome


@Override
public int compareTo(Pessoa outra) {
int resultadoIdade = [Link]([Link], [Link]);
if (resultadoIdade != 0) {
return resultadoIdade;
} else {
return [Link]([Link]);
}
}
}

public class OrdenarPessoasComparable {


public static void main(String[] args) {
List<Pessoa> pessoas = new ArrayList<>();
[Link](new Pessoa("Ana", 30));
[Link](new Pessoa("Carlos", 25));
[Link](new Pessoa("Beatriz", 30));
[Link](new Pessoa("Daniel", 20));

[Link]("Pessoas antes da ordenação: " + pessoas);

[Link](pessoas); // Usa o compareTo da classe Pessoa

[Link]("Pessoas após ordenação (Comparable): " +


pessoas);
// Saída esperada: [Daniel (20), Carlos (25), Ana (30), Beatriz (30)]
}
}

Usando Comparator (com Lambda)


Java
import [Link];
import [Link];
import [Link];

// Reutiliza a classe Pessoa do exemplo anterior, mas não precisa implementar


Comparable
// class Pessoa { ... }

public class OrdenarPessoasComparator {


public static void main(String[] args) {
List<Pessoa> pessoas = new ArrayList<>();
[Link](new Pessoa("Ana", 30));
[Link](new Pessoa("Carlos", 25));
[Link](new Pessoa("Beatriz", 30));
[Link](new Pessoa("Daniel", 20));

[Link]("Pessoas antes da ordenação: " + pessoas);

// Ordena por nome usando um Comparator com lambda


[Link]([Link](p -> [Link]));
[Link]("Pessoas após ordenação por nome (Comparator): " +
pessoas);
// Saída esperada: [Ana (30), Beatriz (30), Carlos (25), Daniel (20)]

// Ordena por idade decrescente usando um Comparator com lambda


[Link]([Link](Pessoa::getIdade).reversed());
[Link]("Pessoas após ordenação por idade decrescente
(Comparator): " + pessoas);
// Saída esperada: [Ana (30), Beatriz (30), Carlos (25), Daniel (20)]
(se getIdade for adicionado à classe Pessoa)
}
}

4. Usando Stream API para Filtrar e Coletar


Java
import [Link];
import [Link];
import [Link];

public class StreamFilterCollect {


public static void main(String[] args) {
List<String> linguagens = [Link]("Java", "Python", "C++",
"JavaScript", "C#", "Ruby");

// Filtrar linguagens que começam com 'J' e coletar em uma nova lista
List<String> linguagensComJ = [Link]()
.filter(s ->
[Link]("J"))

.collect([Link]());

[Link]("Linguagens que começam com 'J': " +


linguagensComJ); // [Java, JavaScript]

// Mapear para o tamanho da string e coletar em um Set (remove


duplicatas de tamanho)
Set<Integer> tamanhosUnicos = [Link]()
.map(String::length) //
Method Reference
.collect([Link]());

[Link]("Tamanhos únicos das linguagens: " +


tamanhosUnicos); // [4, 5, 6, 8, 10]
}
}

Estes exemplos ilustram o uso prático das Collections e sua integração com recursos
modernos do Java. A prática com esses tipos de código é essencial para o concurso.

Pontos de Atenção e Lembretes


Para o concurso da PROCERGS 2025, com foco na banca FUNDATEC e na vaga de Analista
em Computação com ênfase em Programação de Sistemas na Tecnologia JAVA, é
fundamental ter em mente alguns pontos cruciais sobre Collections:
1. Imutabilidade vs. Mutabilidade: A maioria das Collections em Java são mutáveis, ou
seja, seu conteúdo pode ser alterado após a criação. Esteja ciente das implicações
disso, especialmente ao passar coleções como argumentos para métodos ou ao
trabalhar com concorrência. Para coleções imutáveis, use [Link]() ,
[Link]() , etc., ou as coleções imutáveis introduzidas no Java 9
( [Link]() , [Link]() , [Link]() ).
2. Thread-Safety: As implementações padrão de Collections ( ArrayList , HashMap ,
HashSet , LinkedList , TreeMap , TreeSet , PriorityQueue , ArrayDeque ) não são thread-
safe. Se você estiver trabalhando em um ambiente multi-threaded, precisará
sincronizar o acesso à coleção externamente (usando [Link]() ,
[Link]() , etc.) ou usar as classes de concorrência do pacote
[Link] (como ConcurrentHashMap , CopyOnWriteArrayList , BlockingQueue ). A
FUNDATEC pode apresentar cenários de concorrência para testar esse conhecimento.
3. Fail-Fast Iterators: Os iteradores retornados pelas implementações de Collections do
Java são geralmente fail-fast. Isso significa que, se a coleção for modificada
estruturalmente (adição ou remoção de elementos, exceto via método remove() do
próprio iterador) por qualquer thread que não seja o iterador, uma
ConcurrentModificationException será lançada. Isso é uma medida de segurança para
detectar bugs rapidamente.
4. Autoboxing/Unboxing: Ao usar tipos primitivos (int, double, boolean, etc.) com
Collections (que armazenam apenas objetos), o Java realiza automaticamente o
autoboxing (conversão de primitivo para seu wrapper correspondente, ex: int para
Integer ) e unboxing (conversão de wrapper para primitivo). Embora conveniente, isso
pode ter um pequeno impacto na performance e pode levar a NullPointerException se
um wrapper null for unboxed.
5. hashCode() ** e equals() Novamente:** Não subestime a importância desses
métodos. Eles são a base para o funcionamento correto de HashSet , HashMap ,
LinkedHashSet e LinkedHashMap . Uma implementação incorreta é uma fonte comum
de bugs e uma pegadinha frequente em concursos.
6. Escolha da Estrutura Certa: Sempre analise os requisitos do problema:
• Precisa de ordem de inserção? ArrayList , LinkedList , LinkedHashSet , LinkedHashMap .
• Precisa de acesso rápido por índice? ArrayList .
• Precisa de inserção/remoção rápida no início/meio? LinkedList .
• Não pode ter duplicatas? Set (e suas implementações).
• Precisa de elementos ordenados naturalmente ou por critério? TreeSet , TreeMap .
• Precisa de mapeamento chave-valor? Map (e suas implementações).
• Precisa de fila (FIFO) ou pilha (LIFO)? Queue , Deque ( LinkedList , ArrayDeque ).
1. Java 8+ e Programação Funcional: Lembre-se que o Collections Framework é a porta
de entrada para a Stream API. Pratique a conversão de Collections para Streams e o uso
de operações intermediárias e terminais. Entenda como Lambdas e Method References
simplificam o código ao trabalhar com Collections (ex: forEach , removeIf , sort ).
2. Jargão e Nomenclatura: Familiarize-se com os termos técnicos: Collection , List ,
Set , Map , Queue , Deque , Iterator , ListIterator , Comparable , Comparator ,
hashCode , equals , fail-fast , thread-safe , autoboxing , unboxing , Stream API ,
Lambda Expressions , Method References .
Ao manter esses pontos em mente, você estará mais preparado para as nuances e
pegadinhas que a banca FUNDATEC pode apresentar em suas questões sobre o Java
Collections Framework.


Você também pode gostar