O Java completou 30 anos em maio passado e continua firme como uma das linguagens mais usadas em sistemas enterprise. No dia 17 de março de 2026, a Oracle liberou o JDK 26 com 10 JEPs que vão de suporte nativo a HTTP/3 até melhorias no garbage collector G1. É a primeira release não-LTS desde o JDK 25, o que significa que nenhuma dessas features terá suporte estendido. Mas isso não diminui o que está ali dentro.

A proposta desta release é clara: amadurecer APIs que estão em preview há várias versões, limpar código legado (adeus, Applet API) e preparar o terreno para mudanças maiores que devem chegar com o Project Valhalla no JDK 27 ou 28.

As 10 JEPs do JDK 26

O JDK 26 entrega 10 JEPs divididas em quatro eixos: linguagem, bibliotecas, performance e segurança.

No eixo de linguagem, a JEP 530 traz a quarta preview de tipos primitivos em patterns, instanceof e switch. Quem acompanha a evolução do pattern matching desde o JDK 23 já conhece a proposta: permitir que primitivos participem de todos os contextos de pattern matching, com narrowing conversions seguras.

switch (sensor.readTemperature()) {
    case int t when t > 100 -> alertOverheat(t);
    case int t when t < 0 -> alertFreezing(t);
    case int t -> logNormal(t);
}

No eixo de bibliotecas, cinco JEPs concentram as novidades mais relevantes: HTTP/3 para o HttpClient (JEP 517), Structured Concurrency em sexta preview (JEP 525), Lazy Constants em segunda preview (JEP 526), PEM Encodings para objetos criptográficos em segunda preview (JEP 524) e a Vector API na décima primeira incubação (JEP 529).

Do lado de performance, o G1 GC ganha redução de sincronização (JEP 522) e o AOT Object Caching passa a funcionar com qualquer coletor (JEP 516). A JEP 500 antecipa a restrição que tornará final realmente final, emitindo warnings quando reflection tenta mutar campos finais. E a JEP 504 remove de vez a Applet API, deprecated desde o JDK 17.

Nenhuma feature é transformadora isoladamente. Mas o conjunto mostra uma plataforma que está polindo as arestas certas.

HTTP/3 no HttpClient

A JEP 517 adiciona suporte a HTTP/3 no HttpClient API que existe desde o JDK 11. O protocolo roda sobre QUIC em vez de TCP, o que elimina o head-of-line blocking e reduz a latência na abertura de conexão.

O uso é opt-in. Se você não mudar nada, seu HttpClient continua falando HTTP/2:

var client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_3)
    .build();

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.exemplo.com/dados"))
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

O JDK oferece quatro estratégias de negociação de protocolo: timeout com fallback para HTTP/2, race entre os dois protocolos em paralelo, descoberta via header Alt-Svc e modo estrito que falha se não conseguir HTTP/3.

Para quem mantém microsserviços em Java, essa feature é prática. Não precisa trocar de biblioteca HTTP nem adicionar dependência externa. O mesmo HttpClient que você já usa agora fala HTTP/3 com uma linha de configuração.

Structured Concurrency e Lazy Constants

Duas APIs em preview que merecem atenção por onde estão indo.

Structured Concurrency (sexta preview)

A JEP 525 traz Structured Concurrency pela sexta vez em preview. A ideia é tratar tarefas concorrentes como uma unidade: se uma falha, as outras são canceladas automaticamente. Sem thread leaks, sem try/catch espalhado por cinco classes diferentes.

try (var scope = StructuredTaskScope.open()) {
    Supplier<User> user = scope.fork(() -> fetchUser(id));
    Supplier<List<Order>> orders = scope.fork(() -> fetchOrders(id));
    scope.join();
    return new UserProfile(user.get(), orders.get());
}

O scope.join() espera as duas tasks terminarem. Se fetchUser lançar exceção, fetchOrders é cancelada. O escopo garante que nenhuma thread fica pendurada depois que o bloco try termina.

Seis previews podem parecer excessivo, mas cada iteração refinou a API com feedback real. A versão atual inclui joiners como Joiner.anySuccessfulOrThrow() para cenários onde basta o primeiro resultado válido.

Lazy Constants (segunda preview)

A JEP 526 introduz LazyConstant, um holder imutável que inicializa sob demanda:

private final LazyConstant<Logger> logger =
    LazyConstant.of(() -> Logger.create(OrderController.class));

public void processOrder(Order order) {
    logger.get().info("Processando pedido " + order.id());
}

A inicialização acontece na primeira chamada a .get() e é thread-safe por garantia da JVM. Sem double-checked locking manual, sem volatile.

A API também oferece List.ofLazy() e Map.ofLazy() para coleções com inicialização preguiçosa. É o tipo de coisa que frameworks como Spring já faziam por baixo dos panos, agora como primitiva da linguagem. A JVM consegue tratar esses valores como constantes de verdade depois da primeira inicialização, o que abre espaço para otimizações que antes eram impossíveis.

Performance: G1 GC e AOT cache

G1 com menos sincronização

A JEP 522 ataca um ponto que incomoda em workloads pesados: a sincronização entre threads da aplicação e threads do G1 GC.

A solução usa uma arquitetura de dual card table. Enquanto o GC processa uma tabela, a aplicação escreve na outra. As tabelas alternam atomicamente, eliminando a necessidade de locks compartilhados entre os dois lados.

Os benchmarks apontam ganhos de 5 a 15% em throughput para workloads com muitas referências entre objetos. O write barrier foi reduzido de ~50 para 12 instruções em x64, o que traz ganhos de até 5% mesmo em workloads que não manipulam muitas referências entre objetos. Nenhuma flag de configuração é necessária. O G1 mantém a mesma arquitetura externa.

AOT Object Caching com qualquer GC

A JEP 516 expande o cache de objetos ahead-of-time (introduzido no JDK 24) para funcionar com todos os coletores, incluindo o ZGC.

O formato antigo usava endereços de memória diretos, o que amarrava o cache a um GC específico. A solução foi trocar endereços por índices lógicos convertidos de volta em endereços no carregamento. Para forçar o formato compatível, basta a flag -XX:+AOTStreamableObjects. O formato é selecionado automaticamente quando o treinamento usa ZGC ou heaps acima de 32 GB.

Para quem usa ZGC em produção por causa da baixa latência, essa JEP é uma boa notícia: startup mais rápido sem abrir mão do coletor preferido.

O que vem no JDK 27

O JDK 27 está previsto para setembro de 2026 e já tem builds de acesso antecipado disponíveis (Build 14 na data de publicação deste post).

Duas evoluções são esperadas: a terceira preview de Lazy Constants e PEM Encodings, aproximando ambas da versão final. Mas o mais aguardado é outra coisa: features do Project Valhalla, que trariam value classes ao Java.

Value classes permitiriam criar tipos que se comportam como primitivos em performance mas como objetos em expressividade. Essa mudança afeta desde a Vector API (parada na incubação há 11 versões justamente esperando Valhalla) até o uso cotidiano de records e DTOs.

Se Valhalla de fato entregar no JDK 27, será a maior evolução do type system Java em anos. E o próximo LTS, o JDK 29 previsto para setembro de 2027, consolidará tudo que está sendo lapidado agora.

Conclusão

O JDK 26 não é uma release que vai mudar seu código na segunda-feira. Mas é uma release que mostra a direção. HTTP/3 no HttpClient reduz dependências externas. Structured Concurrency amadurece para se tornar a forma padrão de lidar com paralelismo. Lazy Constants trazem inicialização preguiçosa sem gambiarras. E o G1 GC fica mais rápido sem que você precise trocar uma linha de configuração.

Se o seu projeto roda em JDK 21 ou 25 (ambos LTS), o JDK 26 sozinho provavelmente não justifica a migração. Mas vale acompanhar de perto, as features em preview estão convergindo, e quando elas virarem finais, quem já experimentou vai sair na frente.

Para testar, o JDK 26 está disponível no site da Oracle e nas distribuições OpenJDK como Liberica e Adoptium.

Referências pesquisadas nesta publicação