Java8 min de leitura

Programação na era IA

Guia de Sobrevivência: Codificação Inteligente na Era da IA

Com o surgimento do "vibe coding" e do uso em massa de assistentes como GitHub Copilot, ChatGPT, Claude Code e Cursor, a produtividade aumentou, mas o risco de gerar código ineficiente, verboso e com arquitetura falha também cresceu.

Abaixo, compilei as principais lições para manter a qualidade do código Java, garantindo que o "humano no loop" sempre traga a melhor performance e legibilidade.

1. Otimização de Strings: Fuja da Concatenação em Loops

Strings em Java são imutáveis. Toda vez que você concatena strings (usando +), o Java cria um novo objeto. Em loops, isso gera um volume imenso de "lixo" para o Garbage Collector limpar, degradando a performance para algo próximo de O(*N^*2).

O que a IA pode sugerir (Ineficiente):

<span class="hljs-type">String</span> <span class="hljs-variable">resultado</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;
<span class="hljs-keyword">for</span> (String s : lista) {
    resultado += s; <span class="hljs-comment">// Cria um novo objeto a cada iteração!</span>
}

✅ A Boa Prática (Eficiente): Use o StringBuilder. Ele é mutável e muito mais rápido para modificações frequentes.

<span class="hljs-type">StringBuilder</span> <span class="hljs-variable">sb</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();
<span class="hljs-keyword">for</span> (String s : lista) {
    sb.append(s);
}
<span class="hljs-type">String</span> <span class="hljs-variable">resultado</span> <span class="hljs-operator">=</span> sb.toString();

2. Adeus à "Pirâmide do Destino" (Null Checks) Evite o aninhamento excessivo de verificações de nulidade para acessar propriedades de objetos (ex: Pedido -> Cliente -> Endereço -> Cidade). Isso torna o código feio e difícil de manter.

Exemplo "Pirâmide do Destino":

<span class="hljs-keyword">if</span> (pedido != <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">if</span> (pedido.getCliente() != <span class="hljs-literal">null</span>) {
        <span class="hljs-keyword">if</span> (pedido.getCliente().getEndereco() != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">return</span> pedido.getCliente().getEndereco().getCidade();
        }
    }
}

✅ A Boa Prática: Utilize Optional.ofNullable com map. É mais legível, funcional e seguro.

<span class="hljs-keyword">return</span> Optional.ofNullable(pedido)
    .map(Pedido::getCliente)
    .map(Cliente::getEndereco)
    .map(Endereco::getCidade)
    .orElse(<span class="hljs-string">&quot;Desconhecida&quot;</span>);

3. Cuidado com Boxing e Unboxing em Massa

Misturar tipos primitivos (int) com objetos (Integer) dentro de loops adiciona um overhead desnecessário de processamento devido às conversões constantes.

Problema de Overhead:

 <span class="hljs-type">Integer</span> <span class="hljs-variable">soma</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; lista.size(); i++) {
    soma += lista.get(i); <span class="hljs-comment">// Desempacota Integer, soma, e empacota de novo</span>
}

A Boa Prática: Mantenha o processamento em tipos primitivos o máximo possível ou use Streams otimizadas internamente.


4. Expressões Regulares (Regex): Compile uma Única Vez

Compilar um padrão de Regex é uma operação muito cara. Nunca coloque a compilação dentro de um loop.

❌ Erro Comum:

<span class="hljs-keyword">for</span> (String texto : lista) {
    <span class="hljs-keyword">if</span> (Pattern.matches(<span class="hljs-string">&quot;^[1-7, 10, 11]+$&quot;</span>, texto)) { <span class="hljs-comment">// Compila a regex a cada volta!</span>
        <span class="hljs-comment">// ...</span>
    }
}

✅ A Boa Prática: Defina a Regex como uma constante estática final (private static final Pattern) e reuse-a.

<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Pattern</span> <span class="hljs-variable">NUMEROS</span> <span class="hljs-operator">=</span> Pattern.compile(<span class="hljs-string">&quot;^[1-7, 10, 11]+$&quot;</span>);

<span class="hljs-comment">// No loop:</span>
NUMEROS.matcher(texto).matches();

5. Deixe o Compilador JIT Trabalhar por Você Nem toda micro-otimização precisa ser feita manualmente. O JIT (Just-In-Time) Compiler do Java é excelente em:

  • Inlining de Métodos: Se você tem um método pequeno chamado milhares de vezes, o JIT "copia e cola" o código do método diretamente onde ele é chamado para evitar o custo de empilhar chamadas na memória.
  • Código Invariante: O JIT consegue identificar códigos dentro de loops que não mudam de valor e movê-los para fora automaticamente.

6. Sincronização Inteligente

Evite sincronizar métodos inteiros, pois isso pode travar threads desnecessariamente e prejudicar a concorrência do app.

  • Dica: Sincronize apenas o bloco crítico de código ou use classes atômicas como AtomicInteger, que já são thread-safe por natureza.

7. Aproveite os Virtual Threads (Java 21+)

O Java 21 introduziu Virtual Threads (Project Loom), que permitem criar milhares ou até milhões de threads leves sem sobrecarregar o sistema operacional. Isso é especialmente útil para aplicações I/O-bound (ex: requisições HTTP, acesso a banco de dados).

A Boa Prática: Use Executors.newVirtualThreadPerTaskExecutor() para criar pools de virtual threads ao invés de threads tradicionais do sistema operacional.

<span class="hljs-keyword">try</span> (<span class="hljs-type">var</span> <span class="hljs-variable">executor</span> <span class="hljs-operator">=</span> Executors.newVirtualThreadPerTaskExecutor()) {
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10_000</span>; i++) {
        executor.submit(() -&gt; {
            <span class="hljs-comment">// Tarefa I/O-bound aqui</span>
        });
    }
}

8. Pattern Matching e Switch Expressions Modernos

Desde o Java 17, e aprimorado no Java 21, o pattern matching em switch permite código mais limpo e seguro, eliminando muitos instanceof e casts desnecessários.

Forma Antiga:

<span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> String) {
    <span class="hljs-type">String</span> <span class="hljs-variable">s</span> <span class="hljs-operator">=</span> (String) obj;
    System.out.println(s.toUpperCase());
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> Integer) {
    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> (Integer) obj;
    System.out.println(i * <span class="hljs-number">2</span>);
}

✅ A Boa Prática (Java 21+):

<span class="hljs-keyword">switch</span> (obj) {
    <span class="hljs-keyword">case</span> String s -&gt; System.out.println(s.toUpperCase());
    <span class="hljs-keyword">case</span> Integer i -&gt; System.out.println(i * <span class="hljs-number">2</span>);
    <span class="hljs-keyword">case</span> <span class="hljs-literal">null</span> -&gt; System.out.println(<span class="hljs-string">&quot;Valor nulo&quot;</span>);
    <span class="hljs-keyword">default</span> -&gt; System.out.println(<span class="hljs-string">&quot;Tipo desconhecido&quot;</span>);
}

9. Record Classes para DTOs Imutáveis

Os Records (Java 14+) são classes imutáveis compactas, perfeitas para Data Transfer Objects (DTOs). Eles eliminam boilerplate de getters, equals, hashCode e toString.

A Boa Prática:

<span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title class_">Cliente</span><span class="hljs-params">(String nome, String email, <span class="hljs-type">int</span> idade)</span> {}

<span class="hljs-comment">// Uso:</span>
<span class="hljs-type">Cliente</span> <span class="hljs-variable">cliente</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Cliente</span>(<span class="hljs-string">&quot;João&quot;</span>, <span class="hljs-string">&quot;joao@email.com&quot;</span>, <span class="hljs-number">30</span>);
System.out.println(cliente.nome()); <span class="hljs-comment">// Acesso direto</span>

⚠️ Cuidado: Records são imutáveis por design. Se precisar de mutabilidade, use classes tradicionais.


10. Sealed Classes para Hierarquias Controladas

As Sealed Classes (Java 17+) permitem que você restrinja quais classes podem estender ou implementar uma interface/classe, melhorando a segurança de tipo e facilitando pattern matching exaustivo.

<span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">Forma</span> <span class="hljs-keyword">permits</span> Circulo, Retangulo, Triangulo {}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Circulo</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Forma</span> { <span class="hljs-comment">/* ... */</span> }
<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Retangulo</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Forma</span> { <span class="hljs-comment">/* ... */</span> }
<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Triangulo</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Forma</span> { <span class="hljs-comment">/* ... */</span> }

Benefício: O compilador pode verificar que todos os casos foram cobertos em um switch, evitando bugs de casos não tratados.


11. Structured Concurrency (Preview no Java 21+)

A Structured Concurrency organiza tarefas concorrentes em uma estrutura hierárquica, facilitando o tratamento de erros e cancelamento de tarefas relacionadas.

A Boa Prática: Use StructuredTaskScope para gerenciar múltiplas tarefas concorrentes de forma mais previsível.

<span class="hljs-keyword">try</span> (<span class="hljs-type">var</span> <span class="hljs-variable">scope</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StructuredTaskScope</span>.ShutdownOnFailure()) {
    <span class="hljs-type">var</span> <span class="hljs-variable">tarefa1</span> <span class="hljs-operator">=</span> scope.fork(() -&gt; buscarDados1());
    <span class="hljs-type">var</span> <span class="hljs-variable">tarefa2</span> <span class="hljs-operator">=</span> scope.fork(() -&gt; buscarDados2());
    
    scope.join();
    scope.throwIfFailed();
    
    <span class="hljs-type">var</span> <span class="hljs-variable">resultado1</span> <span class="hljs-operator">=</span> tarefa1.get();
    <span class="hljs-type">var</span> <span class="hljs-variable">resultado2</span> <span class="hljs-operator">=</span> tarefa2.get();
}

12. Text Blocks para Strings Multilinha

Os Text Blocks (Java 15+) tornam muito mais fácil trabalhar com strings multilinha, como JSON, SQL, HTML, ou XML, sem concatenações feias.

Forma Antiga:

<span class="hljs-type">String</span> <span class="hljs-variable">json</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;{\n&quot;</span> +
              <span class="hljs-string">&quot;  \&quot;nome\&quot;: \&quot;João\&quot;,\n&quot;</span> +
              <span class="hljs-string">&quot;  \&quot;idade\&quot;: 30\n&quot;</span> +
              <span class="hljs-string">&quot;}&quot;</span>;

✅ A Boa Prática:

<span class="hljs-type">String</span> <span class="hljs-variable">json</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;&quot;
    {
      &quot;nome&quot;: &quot;João&quot;,
      &quot;idade&quot;: 30
    }
    &quot;&quot;&quot;</span>;

13. Evite Stream em Contextos de Alta Performance

Embora Streams sejam elegantes e funcionais, eles adicionam overhead em cenários de alta performance devido à criação de objetos intermediários e boxing/unboxing.

A Boa Prática: Para loops críticos de performance com milhões de iterações, considere usar loops tradicionais (for) ou arrays primitivos ao invés de Streams.


14. Use @Serial para Serialização Segura

O Java 14+ introduziu a anotação @Serial para marcar explicitamente campos e métodos relacionados à serialização, ajudando a evitar erros sutis.

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MinhaClasse</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span> {
    <span class="hljs-meta">@Serial</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">long</span> <span class="hljs-variable">serialVersionUID</span> <span class="hljs-operator">=</span> <span class="hljs-number">1L</span>;
    
    <span class="hljs-meta">@Serial</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">writeObject</span><span class="hljs-params">(ObjectOutputStream out)</span> <span class="hljs-keyword">throws</span> IOException {
        <span class="hljs-comment">// Lógica customizada</span>
    }
}

15. Scoped Values (Preview no Java 21+)

Os Scoped Values são uma alternativa moderna e mais segura ao ThreadLocal, especialmente útil com Virtual Threads. Eles permitem compartilhar dados imutáveis dentro de um escopo definido sem vazamento de memória.

<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> ScopedValue&lt;String&gt;; USER = ScopedValue.newInstance();

ScopedValue.where(USER, <span class="hljs-string">&quot;João&quot;</span>).run(() -&gt; {
    System.out.println(USER.get()); <span class="hljs-comment">// &quot;João&quot;</span>
});

Resumo Visual: Performance vs. Legibilidade

🔴 Problema ✅ Solução 💎 Benefício 🏷️ Tag
Concatenação de Strings em Loop StringBuilder / StringBuffer Performance O(N) ao invés de O(N²) Performance Crítica
ArrayList.contains() repetido HashSet para lookups O(1) vs O(N) Java Básico
Regex compilada em loop Pattern como constante static final Reduz sobrecarga de compilação Performance Crítica
Sincronização de método inteiro Bloco sincronizado ou AtomicInteger Melhor concorrência Threads
Threads tradicionais para I/O Virtual Threads (Java 21+) Milhares de threads leves Java 21+
instanceof + cast repetidos Pattern Matching em Switch Código mais limpo e seguro Java 21+
Boilerplate de DTOs Record Classes Código conciso e imutável Java 14+
Strings multilinha concatenadas Text Blocks Legibilidade extrema Java 15+

Linha do Tempo: Recursos Modernos do Java

💡 Java 14 (2020) -> Records (Preview), Text Blocks, @Serial, Pattern Matching para instanceof (Preview)
Referência: OpenJDK 14

Java 15 (2020) -> Text Blocks (Estável), Sealed Classes (Preview)
Referência: OpenJDK 15

Java 17 LTS (2021) -> Sealed Classes (Estável), Pattern Matching para instanceof (Estável)
Referência: OpenJDK 17

🔥 Java 21 LTS (2023) -> Virtual Threads, Structured Concurrency (Preview), Scoped Values (Preview), Pattern Matching em Switch (Estável)
Referência: OpenJDK 21

🚀 Java 25 LTS (2025) -> PEM Encodings of Cryptographic Objects (Preview), Stable Values (Preview), Remove the 32-bit x86 Port, Structured Concurrency (Fifth Preview), Scoped Values, Primitive Types in Patterns, instanceof, and switch (Third Preview), Vector API (Tenth Incubator), JFR CPU-Time Profiling (Experimental), Key Derivation Function API, Module Import Declarations, Compact Source Files and Instance Main Methods, Flexible Constructor Bodies, Ahead-of-Time Command-Line Ergonomics, Ahead-of-Time Method Profiling, JFR Cooperative Sampling, Compact Object Headers, JFR Method Timing & Tracing, Generational Shenandoah
Referência: OpenJDK 25


Dica Pro: Deixe o JIT Trabalhar

🤖 O Compilador JIT é seu amigo!
Ele já faz automaticamente:

  • Method Inlining: Copia métodos pequenos direto no local de chamada
  • Loop Invariant Hoisting: Move código que não muda para fora do loop
  • Dead Code Elimination: Remove código que nunca é executado

Moral da história: Escreva código limpo primeiro, otimize depois se necessário!


🎓 Checklist Final: Código Java Moderno e Eficiente

  • ☑️ Usar StringBuilder em loops com concatenação
  • ☑️ Preferir HashSet para verificações de existência
  • ☑️ Compilar regex uma única vez como constante
  • ☑️ Sincronizar apenas blocos críticos
  • ☑️ Avaliar Virtual Threads para aplicações I/O-bound
  • ☑️ Usar Pattern Matching em switch quando possível
  • ☑️ Criar DTOs com Records
  • ☑️ Usar Text Blocks para strings multilinha
  • ☑️ Considerar Sealed Classes para hierarquias controladas
  • ☑️ Evitar Streams em contextos de alta performance

💡 Lembre-se: IA pode gerar código rápido, mas você garante que seja código inteligente!


Publicado por: Guilherme Gomes - 10/02/2026 20:29

← Voltar aos Artigos