CodeGym /Cursos /JAVA 25 SELF /Novas coleções: SequencedCollection, SequencedSet, Sequen...

Novas coleções: SequencedCollection, SequencedSet, SequencedMap

JAVA 25 SELF
Nível 34 , Lição 4
Disponível

1. O problema da ordem nas coleções clássicas

No Java sempre houve coleções que garantem a ordem dos elementos (por exemplo, ArrayList, LinkedList, LinkedHashSet, LinkedHashMap), e outras em que a ordem não é garantida (por exemplo, HashSet, HashMap). Mas todas elas tinham uma desvantagem em comum: embora algumas armazenem elementos em uma determinada ordem, as interfaces padrão (List, Set, Map) não forneciam métodos universais para acessar os primeiros e últimos elementos ou para inverter a ordem.

Por exemplo, se você tem um List<String>, pode obter o primeiro elemento com list.get(0), mas para Set ou Map esse truque não funciona — será preciso usar iteradores ou escrever código extra. Convenhamos, isso não é muito prático e não ajuda na legibilidade.

É como se você tivesse um armário com gavetas, mas, para pegar a primeira ou a última, tivesse que contar todas as gavetas manualmente toda vez! Seria ótimo ter alças especiais “primeira” e “última”, não é?

O surgimento de SequencedCollection e interfaces relacionadas

No Java 21 surgiram novas interfaces de coleções:

  • SequencedCollection<E>
  • SequencedSet<E>
  • SequencedMap<K, V>

Essas interfaces estendem as coleções padrão e introduzem uma abordagem unificada para trabalhar com a ordem dos elementos. Agora é possível escrever código universal para quaisquer coleções em que a ordem é importante, sem se preocupar com a implementação concreta.

O que é isso?

  • SequencedCollection — é uma coleção em que os elementos têm uma ordem definida e você pode obter facilmente o primeiro e o último elemento, além de inverter a ordem.
  • SequencedSet — o mesmo, mas para conjuntos (elementos únicos).
  • SequencedMap — o mesmo, mas para mapas (chave-valor).

Quais coleções agora as implementam?

No Java 21, as novas interfaces são implementadas pelas seguintes coleções padrão:

  • ArrayList, LinkedListSequencedCollection
  • LinkedHashSet, TreeSetSequencedSet
  • LinkedHashMap, TreeMapSequencedMap

Isso significa que, se você já usa essas coleções, você automaticamente ganha novos recursos!

2. Métodos principais de SequencedCollection, SequencedSet, SequencedMap

Métodos de SequencedCollection

E getFirst();      // Obter o primeiro elemento
E getLast();       // Obter o último elemento
SequencedCollection<E> reversed(); // Obter a coleção em ordem inversa

Métodos de SequencedSet

Os mesmos métodos que em SequencedCollection, além de tudo o que Set faz.

Métodos de SequencedMap

Map.Entry<K, V> firstEntry();    // Primeira entrada (chave-valor)
Map.Entry<K, V> lastEntry();     // Última entrada (chave-valor)
SequencedMap<K, V> reversed();   // Map em ordem inversa

3. Exemplos de uso das novas interfaces

Exemplo 1: Obtendo o primeiro e o último elemento

import java.util.*;

public class SequencedDemo {
    public static void main(String[] args) {
        SequencedCollection<String> sc = new ArrayList<>();
        sc.add("Java");
        sc.add("Python");
        sc.add("Kotlin");

        // Obter o primeiro e o último elemento
        String first = sc.getFirst(); // "Java"
        String last = sc.getLast();   // "Kotlin"

        System.out.println("Primeiro: " + first);
        System.out.println("Último: " + last);
    }
}

Saída:

Primeiro: Java
Último: Kotlin

Exemplo 2: Invertendo a coleção

SequencedCollection<String> sc = new LinkedList<>();
sc.add("A");
sc.add("B");
sc.add("C");

SequencedCollection<String> reversed = sc.reversed();
System.out.println(reversed); // [C, B, A]

Atenção: reversed() retorna uma visão da coleção em ordem inversa. Se você alterar a coleção original, a visão reversed também mudará!

Exemplo 3: Trabalhando com SequencedSet

SequencedSet<Integer> set = new LinkedHashSet<>();
set.add(100);
set.add(200);
set.add(300);

System.out.println("Primeiro elemento: " + set.getFirst()); // 100
System.out.println("Último elemento: " + set.getLast()); // 300

SequencedSet<Integer> reversedSet = set.reversed();
System.out.println(reversedSet); // [300, 200, 100]

Exemplo 4: Trabalhando com SequencedMap

SequencedMap<String, Integer> map = new LinkedHashMap<>();
map.put("apple", 5);
map.put("banana", 3);
map.put("cherry", 7);

Map.Entry<String, Integer> first = map.firstEntry();
Map.Entry<String, Integer> last = map.lastEntry();

System.out.println("Primeiro: " + first.getKey() + " = " + first.getValue()); // apple = 5
System.out.println("Último: " + last.getKey() + " = " + last.getValue()); // cherry = 7

SequencedMap<String, Integer> reversedMap = map.reversed();
System.out.println(reversedMap); // {cherry=7, banana=3, apple=5}

4. O que isso tem a ver com o seu aplicativo?

Suponha que, no seu aplicativo educacional, você mantenha uma lista de usuários que fizeram login e queira obter rapidamente o primeiro e o último usuário (por exemplo, para mostrar “quem entrou primeiro” e “quem foi o último”). Antes era preciso escrever algo como:

List<String> users = new ArrayList<>();
// ... adicionamos usuários
String first = users.get(0);
String last = users.get(users.size() - 1);

Mas se a coleção não for uma lista, e sim, por exemplo, um LinkedHashSet (em que os elementos são únicos e a ordem é preservada), esse truque não vai funcionar:

Set<String> users = new LinkedHashSet<>();
// ... adicionamos usuários
// Como obter o primeiro? Apenas via iterador:
String first = users.iterator().next();
// E o último? Só percorrendo todos os elementos!

Agora é tudo mais simples e mais universal:

SequencedSet<String> users = new LinkedHashSet<>();
// ... adicionamos usuários
String first = users.getFirst();
String last = users.getLast();

Isso não apenas reduz a quantidade de código, como também o torna mais legível e seguro.

5. Diagrama das novas interfaces

classDiagram
    Collection <|-- SequencedCollection
    List <|-- SequencedCollection
    Set <|-- SequencedSet
    Map <|-- SequencedMap
    SequencedCollection <|-- SequencedSet
    SequencedSet <|-- LinkedHashSet
    SequencedSet <|-- TreeSet
    SequencedCollection <|-- ArrayList
    SequencedCollection <|-- LinkedList
    SequencedMap <|-- LinkedHashMap
    SequencedMap <|-- TreeMap

6. Nuances úteis

Vantagens práticas de SequencedCollection

  • Interface unificada para trabalhar com a ordem: Você não precisa mais lembrar onde existe get(0), onde é necessário um iterador e onde não é possível obter o primeiro elemento.
  • Conveniência ao trabalhar com filas e pilhas: É fácil obter o primeiro (head) e o último (tail) elemento.
  • Segurança e legibilidade: Menos erros relacionados ao uso incorreto de coleções; o código se torna autoexplicativo.
  • Inversão rápida da coleção: O método reversed() permite obter facilmente a ordem inversa sem manipulações manuais.
  • Facilidade de manutenção e evolução do código: Se no futuro você quiser substituir, por exemplo, um ArrayList por um LinkedHashSet, o código que usa SequencedCollection não precisará ser reescrito.

Particularidades de implementação

  • Nem todas as coleções implementam SequencedCollection: Por exemplo, HashSet e HashMap não garantem ordem, portanto não implementam as novas interfaces.
  • Os métodos podem lançar exceções: Se a coleção estiver vazia, chamar getFirst() ou getLast() resultará em NoSuchElementException. Não se esqueça de verificar se a coleção não está vazia!
  • reversed() — é uma visão, não uma cópia: Alterações na coleção original se refletem na visão invertida e vice-versa.
  • Compatibilidade: As novas interfaces estão disponíveis apenas a partir do Java 21. Se você usa uma versão mais antiga do Java, esses recursos ainda não estão disponíveis (mas é um ótimo motivo para atualizar!).
  • Generics: Todas as novas interfaces suportam totalmente generics, então é possível trabalhar com quaisquer tipos de dados.

7. Erros comuns ao trabalhar com SequencedCollection

Erro nº 1: Esperar suporte a ordem de coleções que não a garantem. Se você tentar fazer cast de HashSet para SequencedSet, terá um erro de compilação — o HashSet não tem ordem e não implementa essa interface.

Erro nº 2: Ignorar coleções vazias. Chamar getFirst() ou getLast() em uma coleção vazia lançará uma exceção. Antes de chamar esses métodos, verifique se a coleção não está vazia:

if (!sc.isEmpty()) {
    String first = sc.getFirst();
}

Erro nº 3: Mal-entendidos com reversed(). O método reversed() retorna uma visão, não uma cópia. Se você alterar a visão reversed, a coleção original mudará (e vice-versa). Isso pode levar a resultados inesperados se você não esperar esse comportamento.

Erro nº 4: Usar as novas interfaces em versões antigas do Java. Se seu projeto for compilado com uma versão abaixo do Java 21, o compilador não encontrará essas interfaces. Verifique a versão do JDK nas configurações do projeto!

1
Tarefa
JAVA 25 SELF, nível 34, lição 4
Bloqueado
Gerenciador de tarefas inteligente: verificação de vazio antes de operar 🤖
Gerenciador de tarefas inteligente: verificação de vazio antes de operar 🤖
1
Tarefa
JAVA 25 SELF, nível 34, lição 4
Bloqueado
Algoritmo de etapas: controle direto e reverso 🔄
Algoritmo de etapas: controle direto e reverso 🔄
1
Pesquisa/teste
Coleções modernas, nível 34, lição 4
Indisponível
Coleções modernas
Coleções modernas e imutabilidade
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION