Java

26 mar, 2026

Novidades do Java 26 (para desenvolvedores)

Publicidade

O Java 26 chega com o casamento de padrões em pleno funcionamento, a concorrência caminhando para a finalização e APIs pragmáticas para otimização de inicialização e criptografia. Após o intenso trabalho de linguagem realizado no Java 25, o Java 26 concentra-se em aprimorar as versões prévias existentes e fornecer primitivas de biblioteca que estavam faltando.

Este post é um guia prático: seções curtas, código executável e cenários concretos onde você usará cada recurso em breve. Cada trecho de código é intencionalmente minimalista para que você possa copiar, adaptar e executar rapidamente.

Observação : O Java 26 não é uma versão LTS . Ele recebe atualizações por 6 meses (até setembro de 2026). Para suporte a longo prazo, use o Java 21 LTS ou o Java 25 LTS.

  • [FINAL] — estável, pronto para produção
  • [PRÉ-VISUALIZAÇÃO] — requer--enable-preview
  • [INCUBADOR] — experimental, pode sofrer alterações significativas

Destaques do Java 26

  • [PRÉVIA] Tipos primitivos em padrões em qualquer lugar (JEP 530 – quarta prévia, lançamento em breve)
  • [PRÉVIA] Maturidade da concorrência estruturada (JEP 525 – sexta prévia, próxima da versão final)
  • [PRÉVIA] Constantes preguiçosas para aumento de desempenho na inicialização (JEP 526 – segunda prévia)
  • [PRÉVIA] APIs de criptografia PEM (JEP 524 – segunda prévia)
  • [FINAL] Cache AOT com qualquer GC – incluindo ZGC (JEP 516)
  • [FINAL] HTTP/3 para o Cliente HTTP (JEP 517)
  • [FINAL] Ganhos de desempenho do GC G1 (JEP 522)
  • [FINAL] Campos finais ganhando força (JEP 500 – avisos hoje, negativas depois)
  • [INCUBATOR] API de computação vetorial (JEP 529 – décima primeira incubadora)

Correspondência de linguagem e padrões

JEP 530: Tipos primitivos em padrões, instanceof e switch [PRÉVIA]

JEP 530

O que é: A correspondência de padrões agora funciona uniformemente em todos os tipos primitivos. Você pode usar `std::string` instanceof int x, vincular valores restritos com segurança em `std::string` switche verificar conversões sem perda silenciosa.

Quando você usará: análise de JSON com coerção de tipo, verificações seguras de intervalo numérico, expressão de regras de negócios com guardas.

Antes (conversão manual, verificações de tipo repetitivas):

// BEFORE (Java 25)
public class PriceAnalyzer {
    static String category(Object price) {
        if (price instanceof Integer) {
            int p = (Integer) price;
            return p < 100 ? "BUDGET" : p < 500 ? "MID" : "PREMIUM";
        }
        if (price instanceof Double) {
            double d = (Double) price;
            // Silent truncation risk if cast to int
            if (d > 1000.0) return "PREMIUM";
            return "MID";
        }
        if (price instanceof Long) {
            long l = (Long) price;
            return l > 10_000 ? "PREMIUM" : "BUSINESS";
        }
        return "UNKNOWN";
    }
}

Após (padrões primitivos com estreitamento seguro):

// src/main/java/com/loiane/pricing/Category.java
package com.loiane.pricing;

public class PriceAnalyzer {
    static String category(Object price) {
        return switch (price) {
            case int p when p < 100 -> "BUDGET";
            case int p when p < 500 -> "MID";
            case int p -> "PREMIUM";
            
            case long l when l > 10_000 -> "PREMIUM";
            case long l -> "BUSINESS";
            
            // Only bind d to int x if conversion is exact (no silent loss)
            case double d when d instanceof int x -> 
                "EXACT_INT: " + category(x);
            case double d when d > 1000.0 -> "PREMIUM";
            case double d -> "MID";
            
            default -> "UNKNOWN";
        };
    }

    public static void main(String[] args) {
        System.out.println(category(50));       // BUDGET
        System.out.println(category(300));      // MID
        System.out.println(category(800));      // PREMIUM
        System.out.println(category(15_000L));  // PREMIUM
        System.out.println(category(500.0));    // EXACT_INT
        System.out.println(category(500.5));    // MID
    }
}

O que está acontecendo aqui?

  • case int pvincula-se exatamente a valores inteiros; LongDoubletêm seus próprios casos.
  • d instanceof int xVerifica se o valor double dpode ser convertido exatamente para int (sem perda de precisão); somente então o vincula.
  • Os guards ( when) permitem expressar lógica de intervalo em linha.

Executar (pré-visualização):

javac --enable-preview --release 26 -d out src/main/java/com/loiane/pricing/Category.java
java --enable-preview -cp out com.loiane.pricing.PriceAnalyzer

Concorrência em escala

JEP 525: Concorrência estruturada [PRÉVIA]

JEP 525

O que é: Concorrência baseada em tarefas com cancelamento automático e propagação de erros. Criam-se subtarefas relacionadas, unindo-as em uma unidade; se uma falhar, as demais são canceladas automaticamente.

Quando usar: manipuladores de requisições web, operações de E/S paralelas, fluxos de trabalho com limites claros de sucesso/falha.

Antes (cancelamento manual, vazamentos de threads em caso de falha, tratamento complexo de erros):

// BEFORE (Java 25, using ExecutorService)
public class OrderService {
    static class OrderData {
        String customer;
        List<String> items;
        String address;
    }
    
    static OrderData fetchOrder(ExecutorService executor) throws Exception {
        Future<String> customerFuture = executor.submit(() -> {
            Thread.sleep(100); // simulate I/O
            return "Alice";
        });
        
        Future<List<String>> itemsFuture = executor.submit(() -> {
            Thread.sleep(150);
            return List.of("Laptop", "Mouse");
        });
        
        Future<String> addressFuture = executor.submit(() -> {
            Thread.sleep(200);
            return "123 Main St";
        });
        
        // Problem: if customerFuture.get() throws, itemsFuture and addressFuture
        // keep running (thread leak). Manual cancellation needed everywhere.
        String customer = customerFuture.get();
        List<String> items = itemsFuture.get();
        String address = addressFuture.get();
        
        return new OrderData(customer, items, address);
    }
}

Após (tratamento e cancelamento estruturados e automáticos de erros):

// src/main/java/com/loiane/orders/OrderService.java
package com.loiane.orders;

import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.StructuredTaskScope.Joiner;
import java.util.List;

public class OrderService {
    static class OrderData {
        String customer;
        List<String> items;
        String address;
        
        OrderData(String customer, List<String> items, String address) {
            this.customer = customer;
            this.items = items;
            this.address = address;
        }
    }
    
    static OrderData fetchOrder() throws Exception {
        try (var scope = StructuredTaskScope.open(Joiner.allSuccessfulOrThrow())) {
            var customerTask = scope.fork(() -> {
                Thread.sleep(100);
                return "Alice";
            });
            
            var itemsTask = scope.fork(() -> {
                Thread.sleep(150);
                return List.of("Laptop", "Mouse");
            });
            
            var addressTask = scope.fork(() -> {
                Thread.sleep(200);
                return "123 Main St";
            });
            
            scope.join(); // Wait for all; if any fails, cancel others automatically
            
            return new OrderData(
                customerTask.get(),
                itemsTask.get(),
                addressTask.get()
            );
        }
        // Scope closed: all subtasks guaranteed to have finished
    }
    
    public static void main(String[] args) throws Exception {
        var order = fetchOrder();
        System.out.println("Customer: " + order.customer);
        System.out.println("Items: " + order.items);
        System.out.println("Address: " + order.address);
    }
}

O que está acontecendo aqui?

  • StructuredTaskScope.open(Joiner.allSuccessfulOrThrow())Cria um escopo onde todas as subtarefas devem ser concluídas com sucesso.
  • fork()Inicia cada tarefa assíncrona (thread virtual, por padrão no Java 21+).
  • join()Aguarda a conclusão de todas as subtarefas; se alguma falhar, as outras são canceladas imediatamente.
  • tryO parâmetro -with-resources garante que o escopo seja encerrado e a limpeza seja realizada.

Executar (pré-visualização):

javac --enable-preview --release 26 -d out src/main/java/com/loiane/orders/OrderService.java
java --enable-preview -cp out com.loiane.orders.OrderService

Otimização de startups

JEP 526: Constantes preguiçosas [PRÉVIA]

JEP 526

O que é: Imutabilidade diferida. Cria uma LazyConstant<T>variável que é inicializada no primeiro acesso, com semântica de “no máximo uma vez”, mesmo sob chamadas concorrentes. A JVM a trata como uma constante verdadeira após a inicialização, permitindo otimizações.

Quando usar: Inicialização da aplicação — adie inicializações dispendiosas (loggers, repositórios, configurações) até que sejam necessárias.

Antes (inicialização imediata ou bloqueio com verificação dupla, ambos problemáticos):

// BEFORE
public class Application {
    // Eager: logger created even if app never logs
    private static final Logger LOGGER = Logger.getLogger("com.app");
    
    // Or: double-checked locking (verbose, not constant-folded)
    private static volatile Logger logger;
    static Logger getLogger() {
        if (logger == null) {
            synchronized (Application.class) {
                if (logger == null) {
                    logger = Logger.getLogger("com.app");
                }
            }
        }
        return logger;
    }
}

Após (constante preguiçosa com desempenho de ansioso):

// src/main/java/com/loiane/app/Application.java
package com.loiane.app;

import java.lang.LazyConstant;
import java.util.logging.Logger;

public class Application {
    // Initialize lazily on first call; JVM constant-folds after init
    private static final LazyConstant<Logger> LOGGER =
        LazyConstant.of(() -> Logger.getLogger("com.loiane.app"));
    
    static void logInfo(String msg) {
        LOGGER.get().info(msg);
    }
    
    public static void main(String[] args) {
        logInfo("App started"); // First call: logger created
        logInfo("Processing");  // Subsequent: instant (constant-folded)
    }
}

Para listas, use List.ofLazy():

// src/main/java/com/loiane/app/Pool.java
package com.loiane.app;

import java.util.List;

public class Pool {
    static class Worker {
        String name;
        Worker(String name) { this.name = name; }
    }
    
    // Pool of 10 workers, each created on first access
    static final List<Worker> WORKERS = List.ofLazy(10, 
        index -> new Worker("worker-" + index));
    
    public static void main(String[] args) {
        System.out.println(WORKERS.get(0).name); // Lazy init
        System.out.println(WORKERS.get(0).name); // Instant (cached)
    }
}

O que está acontecendo aqui?

  • LazyConstant.of(supplier)Cria um invólucro; liga para o fornecedor na primeira vez .get(), e nunca mais.
  • List.ofLazy(size, indexedSupplier)Cria uma lista de tamanho fixo com elementos preguiçosos.
  • A JVM otimiza os acessos após a inicialização estar completa.

Executar (pré-visualização):

javac --enable-preview --release 26 -d out src/main/java/com/loiane/app/*.java
java --enable-preview -cp out com.loiane.app.Application

Criptografia e segurança

JEP 524: Codificações PEM de objetos criptográficos [PRÉ-VISUALIZAÇÃO]

JEP 524

O que é: APIs padrão para codificação/decodificação PEM de chaves, certificados e CRLs. Codifica para PEM para armazenamento/transporte; decodifica de PEM de volta para objetos criptográficos Java. Opcionalmente, criptografa chaves privadas.

Quando você usará: Gerenciamento de chaves, carregamento de certificados, compartilhamento seguro de chaves entre sistemas.

Antes (Base64 manual, modelo padrão, sem padrão):

// BEFORE (Java 25)
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.util.Base64;
import java.nio.file.*;

public class KeyMgmt {
    static void exportKey(KeyPair kp) throws Exception {
        byte[] privateKeyBytes = kp.getPrivate().getEncoded();
        String base64 = Base64.getEncoder().encodeToString(privateKeyBytes);
        
        StringBuilder pem = new StringBuilder();
        pem.append("-----BEGIN PRIVATE KEY-----\n");
        // Manually format to 64-char lines
        for (int i = 0; i < base64.length(); i += 64) {
            int end = Math.min(i + 64, base64.length());
            pem.append(base64, i, end).append("\n");
        }
        pem.append("-----END PRIVATE KEY-----\n");
        
        Files.writeString(Path.of("key.pem"), pem);
    }
}

Após (codificador/decodificador PEM limpo com criptografia opcional):

// src/main/java/com/loiane/crypto/KeyMgmt.java
package com.loiane.crypto;

import java.security.*;
import java.security.spec.*;
import java.nio.file.*;
import java.security.PEMEncoder;
import java.security.PEMDecoder;

public class KeyMgmt {
    // Generate a keypair
    static KeyPair generateKeyPair() throws Exception {
        var gen = KeyPairGenerator.getInstance("RSA");
        gen.initialize(2048);
        return gen.generateKeyPair();
    }
    
    // Export keypair to PEM (no encryption)
    static void exportKeyPair(KeyPair kp, Path path) throws Exception {
        String pem = PEMEncoder.of().encodeToString(kp);
        Files.writeString(path, pem);
        System.out.println("Exported: " + path.getFileName());
    }
    
    // Export private key with password encryption
    static void exportEncrypted(KeyPair kp, char[] password, Path path) 
            throws Exception {
        var encoder = PEMEncoder.of().withEncryption(password);
        String pem = encoder.encodeToString(kp.getPrivate());
        Files.writeString(path, pem);
        System.out.println("Exported encrypted: " + path.getFileName());
    }
    
    // Import from PEM
    static KeyPair importKeyPair(Path path, char[] password) throws Exception {
        String pem = Files.readString(path);
        var decoder = PEMDecoder.of().withDecryption(password);
        // Decoder infers type from PEM header
        return (KeyPair) decoder.decode(pem);
    }
    
    public static void main(String[] args) throws Exception {
        var kp = generateKeyPair();
        
        exportKeyPair(kp, Path.of("public-private.pem"));
        exportEncrypted(kp, "secret123".toCharArray(), Path.of("private-encrypted.pem"));
        
        // Re-import
        var restored = importKeyPair(
            Path.of("private-encrypted.pem"),
            "secret123".toCharArray()
        );
        System.out.println("Restored private key: " + restored.getPrivate().getAlgorithm());
    }
}

O que está acontecendo aqui?

  • PEMEncoder.of()Cria um codificador; .encodeToString()retorna o texto PEM diretamente.
  • withEncryption(password)Permite a criptografia baseada em senha para chaves privadas.
  • PEMDecoder.of().withDecryption(password)Detecta automaticamente o tipo de chave a partir do cabeçalho PEM; descriptografa se necessário.

Executar (pré-visualização):

javac --enable-preview --release 26 -d out src/main/java/com/loiane/crypto/KeyMgmt.java
java --enable-preview -cp out com.loiane.crypto.KeyMgmt

JEP 500: Prepare-se para tornar final o significado final [FINAL]

JEP 500

O que é: A reflexão profunda (por exemplo, Field.set()em campos finais) agora emite um aviso. Em uma futura versão do Java, ela lançará uma exceção por padrão. Isso abre caminho para a verdadeira imutabilidade e otimizações da JVM.

Quando usar: Analise os avisos em seus logs e bibliotecas. Use --enable-final-field-mutation=ALL-UNNAMEDem produção se necessário, mas planeje refatorar o código.

Código (detectar mutação do campo final):

// src/main/java/com/loiane/finals/FinalTest.java
package com.loiane.finals;

import java.lang.reflect.Field;

public class FinalTest {
    static class Config {
        final String env = "prod";
    }
    
    public static void main(String[] args) throws Exception {
        Config cfg = new Config();
        System.out.println("Before: " + cfg.env);
        
        // Reflection: mutate the final field
        Field f = Config.class.getDeclaredField("env");
        f.setAccessible(true);
        f.set(cfg, "dev"); // Warning issued in Java 26
        
        System.out.println("After: " + cfg.env);  // Prints "dev"
    }
}

Corra e preste atenção ao aviso:

javac -d out src/main/java/com/loiane/finals/FinalTest.java
java -cp out com.loiane.finals.FinalTest
# Output:
# WARNING: Final field env in class com.loiane.finals.FinalTest$Config
# has been mutated by class com.loiane.finals.FinalTest.main ...

Se precisar suprimir o aviso (temporariamente):

java --illegal-final-field-mutation=allow -cp out com.loiane.finals.FinalTest

Mas planeje migrar as bibliotecas de serialização para sun.reflect.ReflectionFactoryoutra solução.

Desempenho e GC

[FINAL]

JEP 516: Cache de objetos antecipado com qualquer GC [FINAL]

JEP 516

O que é: O cache AOT agora funciona com ZGC, não apenas com G1/Serial/Parallel. Utiliza um formato agnóstico ao GC (índices lógicos), de modo que o mesmo cache funciona em diferentes GCs.

Quando usar: Inicializações a frio de contêineres. Treine com qualquer coletor de lixo; use em produção com Z, G1 ou qualquer outro.

Fluxo de trabalho:

# Training: collect class-loading and object data
java -XX:AOTCacheOutput=app.aot -jar yourapp.jar

# Production: reuse the same cache with ZGC
java -XX:+UseZGC -XX:AOTCache=app.aot -jar yourapp.jar

# or with G1 (the default)
java -XX:AOTCache=app.aot -jar yourapp.jar

Exemplo do Spring Boot (da documentação do JDK): melhoria de 41% no tempo de inicialização do PetClinic (21.000 classes pré-carregadas).

JEP 522: G1 GC: melhorar o rendimento reduzindo a sincronização [FINAL]

JEP 522

O que é: Barreiras de escrita do G1 simplificadas; tabela de cartões dupla elimina a disputa entre os threads do aplicativo e do otimizador de GC. Resultado: ganho de desempenho de 5 a 15% em cargas de trabalho com grande volume de objetos; tempos de pausa ligeiramente menores.

Quando você vai usar: Nada a fazer! As melhorias são automáticas. Acompanhe -XX:+PrintGCDetailsse tiver interesse.

Trecho de teste (das notas de lançamento):

# Before: heavy mutation → GC thread contention
java -XX:+UseG1GC -XX:+PrintGCDetails -jar cpu-intensive-app.jar

# After Java 26: same flags, lower GC overhead
java -XX:+UseG1GC -XX:+PrintGCDetails -jar cpu-intensive-app.jar
# Observe: fewer GC pauses, higher throughput

JEP 517: HTTP/3 para a API do Cliente HTTP [FINAL]

JEP 517

O que é: HttpClientagora suporta HTTP/3 (sobre QUIC). Benefícios: handshakes mais rápidos, sem bloqueio de cabeçalho de fila, resiliente em redes com alta perda de pacotes. Ativação opcional; o padrão é HTTP/2 para compatibilidade.

Quando usar: Ao servir conteúdo de endpoints compatíveis com HTTP/3 (CDNs modernos, balanceadores de carga na nuvem). Compatível com versões anteriores; código existente inalterado.

Código (opt-in HTTP/3 explícito):

// src/main/java/com/loiane/http/Http3Client.java
package com.loiane.http;

import java.net.http.*;
import java.net.URI;

public class Http3Client {
    public static void main(String[] args) throws Exception {
        // Default HTTP/2 client
        var client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .build();
        
        var req = HttpRequest.newBuilder(
                URI.create("https://example.com/api/data"))
                .GET()
                .build();
        
        var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println("Status: " + resp.statusCode());
        System.out.println("Body: " + resp.body());
        
        // HTTP/3 client: opt-in
        var h3Client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_3)
                .build();
        
        var h3Resp = h3Client.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println("HTTP/3 Status: " + h3Resp.statusCode());
        // If server doesn't support HTTP/3, transparently falls back to HTTP/2
    }
}

Computação vetorial (incubação inicial)

JEP 529: API vetorial [INCUBADORA]

JEP 529

O que é: Expressões de operações vetoriais (SIMD) que compilam de forma confiável para AVX, NEON ou SVE. Servem como base VectorSpeciespara definir formato e tamanho; o HotSpot C2 compila para instruções vetoriais de hardware.

Quando usar: Aprendizado de máquina, criptografia, computação numérica, hashing de arrays. Ainda não está pronto para uso geral (em fase de incubação, aguardando o Projeto Valhalla); usado internamente no JDK.

Esboço de código (adição vetorial):

// src/main/java/com/loiane/compute/VectorSum.java
package com.loiane.compute;

import jdk.incubator.vector.*;

public class VectorSum {
    static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
    
    static float[] addVectors(float[] a, float[] b) {
        float[] c = new float[a.length];
        int i = 0;
        
        // Vectorized loop
        int upperBound = SPECIES.loopBound(a.length);
        for (; i < upperBound; i += SPECIES.length()) {
            FloatVector va = FloatVector.fromArray(SPECIES, a, i);
            FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
            FloatVector vc = va.add(vb);
            vc.intoArray(c, i);
        }
        
        // Scalar tail
        for (; i < a.length; i++) {
            c[i] = a[i] + b[i];
        }
        
        return c;
    }
    
    public static void main(String[] args) {
        float[] a = {1.0f, 2.0f, 3.0f, 4.0f};
        float[] b = {5.0f, 6.0f, 7.0f, 8.0f};
        float[] c = addVectors(a, b);
        for (float v : c) System.out.println(v);
    }
}

Compile (add-modules for incubator):

javac --add-modules jdk.incubator.vector -d out \
  src/main/java/com/loiane/compute/VectorSum.java
java --add-modules jdk.incubator.vector -cp out com.loiane.compute.VectorSum

Em CPUs que suportam AVX-512 (por exemplo, Xeon), o HotSpot gera instruções vetorizadas; em CPUs mais antigas, o processo é revertido automaticamente.

Limpeza da plataforma

JEP 504: Remover a API Applet [FINAL]

JEP 504

O que é: java.appletjavax.swing.JApplet, e classes relacionadas foram completamente removidas . Applets não funcionam em navegadores há mais de 10 anos.

Lembra dos aplicativos bancários do início dos anos 2000? Todos eles eram baseados em Applets!

Quando você será afetado: Somente se você mantiver código legado usando applets. Caminho de migração:

  • Contêineres de interface do usuário : Use componentes AWT ou Swing diretamente.
  • Reprodução de áudio : Usar javax.sound.SoundClip(adicionado no Java 25).

Se você encontrar erros de compilação, significa que está modernizando. Isso é progresso.

O que você pode começar a usar hoje

Aqui está um roteiro pragmático para a adoção dos recursos do Java 26 em seus projetos:

Pronto para produção (sem necessidade de sinalizadores) [FINAL]

Comece a usar esses recursos imediatamente em qualquer projeto Java 26:

  • Suporte a HTTP/3 (JEP 517) : Adicione uma única linha para optar por participar; o código existente não será afetado. Risco zero.
    var client = HttpClient.newBuilder()
      .version(HttpClient.Version.HTTP_3)
      .build();
    
  • Cache AOT com qualquer GC (JEP 516) : Melhora o desempenho em inicialização a frio em 30 a 40%. Adicione uma etapa de treinamento em sua CI; envie app.aotpara as imagens de produção. Uma vitória absoluta.
    java -XX:AOTCacheOutput=app.aot -jar app.jar --train
    java -XX:AOTCache=app.aot -jar app.jar  # Production
    
  • Melhorias no G1 GC (JEP 522) : Automático. Nada a fazer; aproveite um ganho de desempenho de 5 a 15% em cargas de trabalho com grande quantidade de objetos.
  • Avisos de campos finais (JEP 500) : Analise os avisos nos logs; coordene com as atualizações de dependências. Nenhuma ação imediata é necessária, a menos que se utilize reflexão profunda nos campos finais.

Seguro para adoção em desenvolvimento/teste [PRÉVIA]

Essas funcionalidades são estáveis ​​e serão implementadas em breve. Use-as em desenvolvimento e testes; planeje a implementação em produção quando estiverem finalizadas.

  • Padrões de tipo primitivo (JEP 530) : Quarta prévia; caminho claro para a finalização. Adote em novos códigos e refatore bases de código com alta dependência de recursos avançados.
    if (value instanceof int x) { ... }
    switch (price) {
      case long l when l > 10_000 -> "PREMIUM";
      ...
    }
    

    Adicionar ao pipeline de construção: javac --enable-preview --release 26.

  • Concorrência estruturada (JEP 525) : Sexta prévia; comprovada em aplicações reais. Use para todo novo código concorrente.
    try (var scope = StructuredTaskScope.open(Joiner.allSuccessfulOrThrow())) {
      var t1 = scope.fork(() -> ...);
      var t2 = scope.fork(() -> ...);
      scope.join();
      return new Result(t1.get(), t2.get());
    }
    
  • Constantes preguiçosas (JEP 526) : Segunda prévia; API estável. Use para otimizar a inicialização do aplicativo.
    static final LazyConstant<Logger> LOGGER = 
      LazyConstant.of(() -> Logger.getLogger("app"));
    
  • Codificações PEM (JEP 524) : Segunda prévia; simples. Use para manipulação de chaves/certificados criptográficos:
    var kp = KeyPairGenerator.getInstance("RSA").generateKeyPair();
    String pem = PEMEncoder.of().encodeToString(kp);
    

Experimental (incubadoras) — aguardar finalização

  • API Vector (JEP 529) : Décima primeira incubadora; depende do Projeto Valhalla. Ainda não recomendada para uso em produção. Acompanhe a conclusão no Java 27/28.

Lista de verificação para migração

Se você é um dos primeiros a adotar o Java 26:

  1. Ative as pré-visualizações na sua compilação :
    <!-- Maven -->
    <release>26</release>
    <args>
      <arg>--enable-preview</arg>
    </args>
    
  2. Atualização de CI/CD :
    • Baixe o JDK 26 GA.
    • Configure a geração de cache AOT nas etapas de treinamento (opcional, mas recomendado).
    • Teste --enable-previewpara detectar depreciações precocemente.
  3. Refatorar incrementalmente :
    • Novo código: usar padrões primitivos, concorrência estruturada e constantes preguiçosas.
    • Código legado: adote conforme o tempo permitir; esses recursos não são disruptivos.
  4. Plano para migração para LTS :
    • Java 26 = 6 meses de atualizações (até setembro de 2026).
    • ou permaneça usando o Java 21 LTS ou o Java 25 LTS até lá.

Notas

  • Os recursos de pré-visualização e incubação exigem --enable-previewe/ou --add-modules.
  • Os padrões primitivos (JEP 530) estão na reta final: a quarta prévia sugere a finalização no Java 27 ou 28.
  • A concorrência estruturada (JEP 525) também está em um nível de maturidade semelhante; planeje usá-la em novos códigos concorrentes hoje mesmo.
  • As constantes preguiçosas e as codificações PEM estão em fase de refinamento; pequenos ajustes na API são possíveis antes da versão final.
  • A API Vector deixará de estar em fase de incubação assim que o Projeto Valhalla entregar classes de valor; ainda não é recomendada para produção fora do próprio JDK.
  • A implementação final das restrições de campo envolve várias versões: avisos na versão 26 e proibições em uma versão futura. Planeje suas migrações agora.

Referências

Boa programação!