Java8 min de leitura

Java Internals: O Custo Cognitivo da Imutabilidade de Strings

Java Internals: O Custo Cognitivo da Imutabilidade de Strings

Imutabilidade de String - JVM


Introdução

Você já fez code review e encontrou algo assim?

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">public</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">static</span>&lt;/span&gt;&amp;lt;/span&amp;gt; String &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title function_&amp;quot;&lt;/span&gt;&amp;gt;stopIt&amp;lt;/span&amp;gt;&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-params&amp;quot;&lt;/span&gt;&amp;gt;(String str)&amp;lt;/span&amp;gt; {
    str.replace(str, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// parece certo...&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
    &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; str;               &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// mas retorna &amp;amp;quot;start&amp;amp;quot;&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

A primeira reação costuma ser: "como esse dev não sabia que String é imutável?"

A resposta honesta é: ele provavelmente sabia. O problema não é falta de conhecimento - é o que podemos chamar de custo cognitivo da semântica verbal.


O Problema: a Semântica dos Verbos

Verbos como replace, trim, toUpperCase e toLowerCase carregam uma carga semântica de ação direta. O cérebro os processa como modificadores - da mesma forma que list.add() ou map.put() realmente alteram o estado do objeto.

Essa é a armadilha. Não é que o desenvolvedor esqueceu a imutabilidade. É que a leitura fluida do código ativa um padrão cognitivo diferente da realidade da JVM.

Veja a diferença de comportamento com coleções mutáveis:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// List é mutável - add() modifica o estado diretamente&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
List&amp;amp;lt;String&amp;amp;gt; list = &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">new</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title class_&amp;quot;&lt;/span&gt;&amp;gt;ArrayList&amp;lt;/span&amp;gt;&amp;amp;lt;&amp;amp;gt;();
list.add(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;item&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// funciona como esperado&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
System.out.println(list); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// [item]&amp;lt;/span&amp;gt;&lt;/span&gt;</span>

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// String é imutável - replace() não modifica nada&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;texto&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;start&amp;amp;quot;&amp;lt;/span&amp;gt;;
texto.replace(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;start&amp;amp;quot;&amp;lt;/span&amp;gt;, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// resultado descartado silenciosamente&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
System.out.println(texto); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// &amp;amp;quot;start&amp;amp;quot;&amp;lt;/span&amp;gt;&lt;/span&gt;</span>

O compilador não avisa. O IDE pode (e deve) alertar, mas em projetos com muitos warnings suprimidos, esse erro passa despercebido facilmente.


O que Acontece na JVM

Quando uma String é criada, seu conteúdo é alocado no String Constant Pool (SCP) - uma área especial da heap gerenciada pela JVM. Uma vez lá, o conteúdo é imutável e fixo.

Quando você chama str.replace(str, "stop"), a JVM:

  1. Lê o conteúdo original de str no SCP
  2. Cria um novo objeto String com o valor "stop"
  3. Retorna a referência para esse novo objeto
  4. Descarta a referência se você não a capturar

O objeto original não é tocado. A variável str continua apontando para "start".

SCP (String Constant Pool)
┌──────────────┐     ┌──────────────┐
│   &amp;amp;quot;start&amp;amp;quot;    │     │    &amp;amp;quot;stop&amp;amp;quot;    │
│  (imutável)  │     │ (nova inst.) │
└──────┬───────┘     └──────┬───────┘
       │                    │
       str             ← referência descartada se não capturada

A Solução: Captura Explícita da Nova Referência

Métodos de manipulação de String não são mutators (modificadores de estado). São fábricas de novos objetos. Para que a alteração persista, a nova referência precisa ser explicitamente capturada:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✗ Errado - resultado descartado&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">public</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">static</span>&lt;/span&gt;&amp;lt;/span&amp;gt; String &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title function_&amp;quot;&lt;/span&gt;&amp;gt;stopIt&amp;lt;/span&amp;gt;&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-params&amp;quot;&lt;/span&gt;&amp;gt;(String str)&amp;lt;/span&amp;gt; {
    str.replace(str, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;);
    &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; str; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// retorna &amp;amp;quot;start&amp;amp;quot;&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ Correto - nova instância capturada&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">public</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">static</span>&lt;/span&gt;&amp;lt;/span&amp;gt; String &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title function_&amp;quot;&lt;/span&gt;&amp;gt;stopIt&amp;lt;/span&amp;gt;&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-params&amp;quot;&lt;/span&gt;&amp;gt;(String str)&amp;lt;/span&amp;gt; {
    &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; str.replace(str, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// retorna &amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

O mesmo padrão se aplica a toda a API de String:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;nome&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;  guilherme  &amp;amp;quot;&amp;lt;/span&amp;gt;;

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✗ Errado&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
nome.trim();
nome.toUpperCase();

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ Correto&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
nome = nome.trim().toUpperCase();
System.out.println(nome); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// &amp;amp;quot;GUILHERME&amp;amp;quot;&amp;lt;/span&amp;gt;&lt;/span&gt;</span>

Por que a Imutabilidade Existe

A imutabilidade das Strings não é uma limitação - é uma decisão arquitetural deliberada que viabiliza otimizações críticas na JVM:

1. String Constant Pool e Compartilhamento de Referências

O SCP permite que literais idênticos compartilhem a mesma referência em memória:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;a&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Java&amp;amp;quot;&amp;lt;/span&amp;gt;;
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;b&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Java&amp;amp;quot;&amp;lt;/span&amp;gt;;

System.out.println(a == b); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// true - mesma referência no SCP&amp;lt;/span&amp;gt;&lt;/span&gt;</span>

Se Strings fossem mutáveis, compartilhar referências seria perigoso: alterar a afetaria b.

2. Thread Safety Nativa

Strings são inerentemente thread-safe. Não há necessidade de synchronized, volatile ou locks para compartilhar uma String entre threads, porque nenhuma thread pode modificar seu conteúdo.

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// Seguro compartilhar entre threads sem qualquer sincronização&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;endpoint&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;https:&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">//getcaramelo.dev/v1/posts&amp;amp;quot;&amp;lt;/span&amp;gt;;&lt;/span&gt;</span>

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;ExecutorService&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;pool&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; Executors.newVirtualThreadPerTaskExecutor();
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">for</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-type&quot;</span>&gt;<span class="hljs-type">int</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;i&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-number&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-number&quot;</span>&gt;<span class="hljs-number">0</span>&lt;/span&gt;&amp;lt;/span&amp;gt;; i &amp;amp;lt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-number&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-number&quot;</span>&gt;<span class="hljs-number">100</span>&lt;/span&gt;&amp;lt;/span&amp;gt;; i++) {
    pool.submit(() -&amp;amp;gt; fetch(endpoint)); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// endpoint é imutável, sem risco&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

3. String Deduplication (G1GC)

O G1 Garbage Collector possui uma otimização chamada String Deduplication: ele identifica objetos String com conteúdo idêntico em diferentes regiões da heap e consolida suas referências para apontar ao mesmo char[] interno. Isso só é possível porque o conteúdo é imutável - a JVM tem a garantia de que ninguém vai alterá-lo por baixo dos panos.

4. HashCode Cacheado

O hashCode() de uma String é computado uma vez e armazenado internamente. Como o conteúdo nunca muda, o cache é sempre válido - o que torna operações com HashMap<String, ?> mais eficientes do que com objetos mutáveis equivalentes.


Quando Você Precisa de Mutabilidade: StringBuilder

Toda vez que você precisa construir uma String em múltiplos passos, o StringBuilder entra em cena - mas usá-lo em todos os casos é um exagero que pode custar em legibilidade sem ganho real de performance.

O Cenário Crítico: Concatenação em Loops

O uso do operador + dentro de um loop é o principal caso onde o StringBuilder deve ser preferido explicitamente. Cada iteração com + pode criar um novo objeto String intermediário na heap, gerando lixo que o GC precisará processar. Em volumes altos, isso resulta em complexidade de tempo O(n²):

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✗ Ineficiente - potencialmente O(n²)&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// cada iteração cria um objeto String descartável&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;resultado&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;&amp;amp;quot;&amp;lt;/span&amp;gt;;
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">for</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (String parte : partes) {
    resultado += parte;
}

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ Eficiente - O(n)&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// uma única instância de buffer, append in-place&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;StringBuilder&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;sb&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">new</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title class_&amp;quot;&lt;/span&gt;&amp;gt;StringBuilder&amp;lt;/span&amp;gt;();
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">for</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (String parte : partes) {
    sb.append(parte);
}
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;resultado&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; sb.toString();

O mesmo vale para construção condicional ao longo de múltiplos passos de lógica:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ StringBuilder faz sentido aqui - construção incremental e condicional&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;StringBuilder&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;query&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">new</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title class_&amp;quot;&lt;/span&gt;&amp;gt;StringBuilder&amp;lt;/span&amp;gt;(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;SELECT * FROM users WHERE &lt;span class=<span class="hljs-string">&quot;hljs-number&quot;</span>&gt;<span class="hljs-number">1</span>&lt;/span&gt;=&lt;span class=<span class="hljs-string">&quot;hljs-number&quot;</span>&gt;<span class="hljs-number">1</span>&lt;/span&gt;&amp;amp;quot;&amp;lt;/span&amp;gt;);
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">if</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (filtroNome != &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-literal&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-literal&quot;</span>&gt;<span class="hljs-literal">null</span>&lt;/span&gt;&amp;lt;/span&amp;gt;)   query.append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot; &lt;span class=<span class="hljs-string">&quot;hljs-type&quot;</span>&gt;AND&lt;/span&gt; &lt;span class=<span class="hljs-string">&quot;hljs-variable&quot;</span>&gt;nome&lt;/span&gt; &lt;span class=<span class="hljs-string">&quot;hljs-operator&quot;</span>&gt;=&lt;/span&gt; &amp;amp;#x27;&amp;amp;quot;&amp;lt;/span&amp;gt;).append(filtroNome).append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;&amp;amp;#x27;&amp;amp;quot;&amp;lt;/span&amp;gt;);
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">if</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (filtroAtivo != &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-literal&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-literal&quot;</span>&gt;<span class="hljs-literal">null</span>&lt;/span&gt;&amp;lt;/span&amp;gt;)  query.append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot; &lt;span class=<span class="hljs-string">&quot;hljs-type&quot;</span>&gt;AND&lt;/span&gt; &lt;span class=<span class="hljs-string">&quot;hljs-variable&quot;</span>&gt;ativo&lt;/span&gt; &lt;span class=<span class="hljs-string">&quot;hljs-operator&quot;</span>&gt;=&lt;/span&gt; &amp;amp;quot;&amp;lt;/span&amp;gt;).append(filtroAtivo);
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">if</span>&lt;/span&gt;&amp;lt;/span&amp;gt; (limite &amp;amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-number&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-number&quot;</span>&gt;<span class="hljs-number">0</span>&lt;/span&gt;&amp;lt;/span&amp;gt;)           query.append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot; LIMIT &amp;amp;quot;&amp;lt;/span&amp;gt;).append(limite);
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; query.toString();

Onde o + Vence: Concatenação Simples

Para concatenações diretas em uma única instrução, o compilador e a JVM já fazem o trabalho por você - e fazem bem.

No JDK 8, o compilador transformava internamente "A" + "B" + "C" em uma implementação de StringBuilder no bytecode. A partir do JDK 9, o JEP 280 introduziu a Indify String Concatenation: a instrução invokedynamic delega a operação à JVM de forma dinâmica, permitindo otimizações que nem aparecem no bytecode e que evoluem com as versões do Java sem recompilação.

Na prática, benchmarks em máquinas modernas mostram que a concatenação via + em casos simples pode ser mais rápida do que o uso explícito de StringBuilder:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ Deixa o compilador/JVM otimizar - é a escolha certa aqui&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;mensagem&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Olá, &amp;amp;quot;&amp;lt;/span&amp;gt; + nome + &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;! Bem-vindo ao &amp;amp;quot;&amp;lt;/span&amp;gt; + plataforma + &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;.&amp;amp;quot;&amp;lt;/span&amp;gt;;

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✗ Desnecessariamente verbose - sem ganho de performance&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;mensagem&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">new</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title class_&amp;quot;&lt;/span&gt;&amp;gt;StringBuilder&amp;lt;/span&amp;gt;()
    .append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Olá, &amp;amp;quot;&amp;lt;/span&amp;gt;).append(nome)
    .append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;! Bem-vindo ao &amp;amp;quot;&amp;lt;/span&amp;gt;).append(plataforma).append(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;.&amp;amp;quot;&amp;lt;/span&amp;gt;)
    .toString();

Alternativas Modernas para Legibilidade

Quando o objetivo é legibilidade na construção de texto dinâmico - XML, JSON, SQL, templates - existem alternativas mais expressivas que o StringBuilder:

Text Blocks (JDK 15+) para strings multilinhas fixas:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;json&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;&amp;amp;quot;&amp;amp;quot;
        {
            &amp;amp;quot;nome&amp;amp;quot;: &amp;amp;quot;%s&amp;amp;quot;,
            &amp;amp;quot;ativo&amp;amp;quot;: %b
        }
        &amp;amp;quot;&amp;amp;quot;&amp;amp;quot;&amp;lt;/span&amp;gt;.formatted(nome, ativo);

String.formatted() como alternativa legível ao String.format() - mesmo resultado, sintaxe mais fluida:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// String.format() - clássico&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;msg&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; String.format(&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Usuário %s criado em %s&amp;amp;quot;&amp;lt;/span&amp;gt;, nome, data);

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// String.formatted() - mais idiomático desde o Java 15&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-type&amp;quot;&lt;/span&gt;&amp;gt;String&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-variable&amp;quot;&lt;/span&gt;&amp;gt;msg&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-operator&amp;quot;&lt;/span&gt;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;Usuário %s criado em %s&amp;amp;quot;&amp;lt;/span&amp;gt;.formatted(nome, data);

⚠️ Evite String.format() e String.formatted() dentro de loops de alta frequência. Ambos são consideravelmente mais lentos que StringBuilder ou concatenação simples por envolverem parsing de formato a cada chamada.

Guia de Decisão Rápido

Cenário Use
Concatenar poucas variáveis em uma linha + ou String.formatted()
Construir String dentro de loop StringBuilder
Construção incremental com condicionais StringBuilder
Template multiline com valores fixos Text Block
Template multiline com interpolação Text Block + .formatted()
Alta frequência em loop crítico StringBuilder (evite format)

Revisitando o Código Original

Com tudo isso em mente, o erro inicial fica mais claro:

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✗ Versão com o erro&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">public</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">static</span>&lt;/span&gt;&amp;lt;/span&amp;gt; String &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title function_&amp;quot;&lt;/span&gt;&amp;gt;stopIt&amp;lt;/span&amp;gt;&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-params&amp;quot;&lt;/span&gt;&amp;gt;(String str)&amp;lt;/span&amp;gt; {
    str.replace(str, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// cria &amp;amp;quot;stop&amp;amp;quot; na heap, referência perdida&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
    &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; str;               &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// str ainda aponta para &amp;amp;quot;start&amp;amp;quot; no SCP&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// ✓ Versão correta&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">public</span>&lt;/span&gt;&amp;lt;/span&amp;gt; &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">static</span>&lt;/span&gt;&amp;lt;/span&amp;gt; String &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-title function_&amp;quot;&lt;/span&gt;&amp;gt;stopIt&amp;lt;/span&amp;gt;&amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-params&amp;quot;&lt;/span&gt;&amp;gt;(String str)&amp;lt;/span&amp;gt; {
    &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-keyword&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-keyword&quot;</span>&gt;<span class="hljs-keyword">return</span>&lt;/span&gt;&amp;lt;/span&amp;gt; str.replace(str, &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-string&amp;quot;&lt;/span&gt;&amp;gt;&amp;amp;quot;stop&amp;amp;quot;&amp;lt;/span&amp;gt;); &amp;lt;span class=&lt;span class=<span class="hljs-string">&quot;hljs-string&quot;</span>&gt;&amp;quot;hljs-comment&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class=<span class="hljs-string">&quot;hljs-comment&quot;</span>&gt;<span class="hljs-comment">// captura e retorna a nova referência&amp;lt;/span&amp;gt;&lt;/span&gt;</span>
}

O erro não é conceitual - é de leitura. replace soa como uma operação in-place. Para quem lê rápido (e revisores de PR leem rápido), o olho passa e o cérebro valida. Saber disso é o que separa um bom code reviewer de um revisor médio.


Conclusão

Imutabilidade de Strings em Java não é um detalhe trivial de documentação. É uma decisão que impacta gerenciamento de memória, segurança em concorrência e performance do GC. O custo cognitivo existe - e conhecê-lo te torna mais atento tanto ao escrever quanto ao revisar código.

Na próxima vez que você ver um verbo como replace, trim ou toUpperCase em uma revisão, a pergunta certa é simples: o resultado foi capturado?


Este artigo faz parte da série Objects · Immutability · Switch · Pattern Matching do getcaramelo.dev.

Tem dúvidas ou quer aprofundar algum ponto? Me encontra no LinkedIn ou no GitHub.

Publicado por: Guilherme Gomes - 28/06/2026 15:10

Gostou do conteúdo? Me segue no @getcaramelo.dev

← Voltar aos Artigos