Especialização em Sistemas com Java 21 LTS • Capítulo 13


🎯 Visão Geral dos Exemplos Práticos

Neste laboratório prático, implementaremos exemplos corporativos completos explorando:

  1. Cache LRU (Least Recently Used) com LinkedHashMap: política de despejo automático de entradas expiradas baseada na ordem de acesso.
  2. Índice Ordenado com TreeMap e Navegação Range: busca eficiente de faixas de valores (subMap, tailMap, headMap).
  3. Mecanismo Genérico de Transferência com PECS: métodos utilitários aplicando covariância (? extends T) e contravariância (? super T).

💻 Exemplo 01 — Cache LRU de Sessões e Catálogo com TreeMap

package com.empresa.colecoes;

import java.math.BigDecimal;
import java.util.*;

/**
 * Cache de alta performance e índice ordenado em árvore balanceada.
 */
public class SistemaCacheEIndices {

    public record SessaoUsuario(String usuario, String ip, long timestampLogin) {}
    public record AtivoFinanceiro(String ticker, BigDecimal cotacao) implements Comparable<AtivoFinanceiro> {
        @Override
        public int compareTo(AtivoFinanceiro outro) {
            return this.ticker.compareTo(outro.ticker);
        }
    }

    // Cache LRU que expulsa automaticamente as entradas menos recentemente acessadas
    public static class CacheLruSessoes<K, V> extends LinkedHashMap<K, V> {
        private final int maxEntradas;

        public CacheLruSessoes(int maxEntradas) {
            super(maxEntradas, 0.75f, true); // true = access-order
            this.maxEntradas = maxEntradas;
        }

        @Override
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            boolean deveRemover = size() > maxEntradas;
            if (deveRemover) {
                System.out.printf("   [CACHE EVICTION] Expulsando chave expirada: %s%n", eldest.getKey());
            }
            return deveRemover;
        }
    }

    public static void main(String[] args) {
        System.out.println("================================================================================");
        System.out.println("             CACHE LRU E ÍNDICES EM ÁRVORE RUBRO-NEGRA (JAVA 21)                ");
        System.out.println("================================================================================");

        // 1. Teste de Cache LRU
        System.out.println("--- 1. Demonstração de Evicção do Cache LRU (Limite 3) ---");
        CacheLruSessoes<String, SessaoUsuario> cache = new CacheLruSessoes<>(3);

        cache.put("SESS-01", new SessaoUsuario("admin", "192.168.1.10", System.currentTimeMillis()));
        cache.put("SESS-02", new SessaoUsuario("financeiro", "192.168.1.15", System.currentTimeMillis()));
        cache.put("SESS-03", new SessaoUsuario("suporte", "192.168.1.20", System.currentTimeMillis()));

        System.out.println("Sessões no cache: " + cache.keySet());

        // Acessamos SESS-01 -> Torna-se o mais recentemente usado
        System.out.println("Acessando SESS-01...");
        cache.get("SESS-01");

        // Inserimos SESS-04 -> Deve expulsar SESS-02 (o mais antigo sem acesso)
        System.out.println("Inserindo SESS-04...");
        cache.put("SESS-04", new SessaoUsuario("auditoria", "192.168.1.50", System.currentTimeMillis()));

        System.out.println("Sessões sobreviventes no cache: " + cache.keySet());

        // 2. Teste de TreeMap com Navegação Range
        System.out.println("\n--- 2. Livro de Ofertas e Índices com TreeMap (O(log n)) ---");
        NavigableMap<String, AtivoFinanceiro> livroOfertas = new TreeMap<>();
        livroOfertas.put("PETR4", new AtivoFinanceiro("PETR4", new BigDecimal("37.80")));
        livroOfertas.put("VALE3", new AtivoFinanceiro("VALE3", new BigDecimal("62.40")));
        livroOfertas.put("ITUB4", new AtivoFinanceiro("ITUB4", new BigDecimal("33.15")));
        livroOfertas.put("BBDC4", new AtivoFinanceiro("BBDC4", new BigDecimal("14.50")));
        livroOfertas.put("WEGE3", new AtivoFinanceiro("WEGE3", new BigDecimal("51.20")));

        System.out.println("Ativos ordenados lexicograficamente:");
        livroOfertas.forEach((ticker, ativo) -> 
            System.out.printf("   Ticker: %-6s | Cotação: R$ %6.2f%n", ticker, ativo.cotacao()));

        // Intervalo de mercado (Range Query de ITUB4 até PETR4)
        System.out.println("\nSub-mapa no intervalo [ITUB4 até PETR4]:");
        SortedMap<String, AtivoFinanceiro> subMapa = livroOfertas.subMap("ITUB4", "PETR4\0");
        subMapa.forEach((ticker, ativo) -> 
            System.out.printf("   ➡️ %-6s : R$ %6.2f%n", ticker, ativo.cotacao()));

        System.out.println("================================================================================");
    }
}

💻 Exemplo 02 — Implementação Rigorosa do Princípio PECS

package com.empresa.colecoes;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * Utilitário genérico de processamento com covariância e contravariância.
 */
public class ProcessadorColecoesPecs {

    public static abstract class Transacao {
        private final String id;
        private final BigDecimal valor;
        public Transacao(String id, BigDecimal valor) { this.id = id; this.valor = valor; }
        public String getId() { return id; }
        public BigDecimal getValor() { return valor; }
    }

    public static class PixTransacao extends Transacao {
        public PixTransacao(String id, BigDecimal valor) { super(id, valor); }
    }

    public static class TedTransacao extends Transacao {
        public TedTransacao(String id, BigDecimal valor) { super(id, valor); }
    }

    // PECS: Origem é PRODUTORA (extends) e Destino é CONSUMIDORA (super)
    public static <T extends Transacao> void transferirLote(
            List<? extends T> produtor,
            List<? super T> consumidor) {
        for (T elemento : produtor) {
            consumidor.add(elemento); // Consumidor recebe elementos com segurança
        }
    }

    public static void main(String[] args) {
        List<PixTransacao> lotePix = List.of(
            new PixTransacao("PIX-1", new BigDecimal("100.00")),
            new PixTransacao("PIX-2", new BigDecimal("250.00"))
        );

        List<Transacao> ledgerGeral = new ArrayList<>();
        transferirLote(lotePix, ledgerGeral); // Compila com perfeição graças a PECS!

        System.out.println("Itens consolidados no ledger geral:");
        for (Transacao tx : ledgerGeral) {
            System.out.printf("   TX ID: %s | Valor: R$ %.2f%n", tx.getId(), tx.getValor());
        }
    }
}

📋 Resultado Esperado no Console

================================================================================
             CACHE LRU E ÍNDICES EM ÁRVORE RUBRO-NEGRA (JAVA 21)                
================================================================================
--- 1. Demonstração de Evicção do Cache LRU (Limite 3) ---
Sessões no cache: [SESS-01, SESS-02, SESS-03]
Acessando SESS-01...
Inserindo SESS-04...
   [CACHE EVICTION] Expulsando chave expirada: SESS-02
Sessões sobreviventes no cache: [SESS-03, SESS-01, SESS-04]

--- 2. Livro de Ofertas e Índices com TreeMap (O(log n)) ---
Ativos ordenados lexicograficamente:
   Ticker: BBDC4  | Cotação: R$  14.50
   Ticker: ITUB4  | Cotação: R$  33.15
   Ticker: PETR4  | Cotação: R$  37.80
   Ticker: VALE3  | Cotação: R$  62.40
   Ticker: WEGE3  | Cotação: R$  51.20

Sub-mapa no intervalo [ITUB4 até PETR4]:
   ➡️ ITUB4  : R$  33.15
   ➡️ PETR4  : R$  37.80
================================================================================
Itens consolidados no ledger geral:
   TX ID: PIX-1 | Valor: R$ 100.00
   TX ID: PIX-2 | Valor: R$ 250.00