← início

Strings em Java

Strings em Java

Fala galera, beleza? Hoje vou destrinchar uma das classes mais usadas no dia a dia de qualquer programador Java: a String. Parece simples — afinal, é “só texto”, né? — mas tem muita coisa por trás que, quando você entende, evita um monte de bug bobo. Bora lá!

O que é uma String, afinal?

De forma bem direta: uma String é uma sequência de caracteres. Tipo "Goku", "Hello World" ou "123abc". Mas aqui já vem a primeira pegadinha que muita gente não percebe:

Em Java, String não é um tipo primitivo — é uma classe. Ou seja, toda vez que você cria uma String, você está criando um objeto.

Lembra do artigo sobre primitivos e wrappers? Pois é, a String mora no mesmo bairro dos wrappers: é objeto, vive no heap, tem métodos. Só que com algumas peculiaridades bem próprias.

String nome = "Gabriel";
// Por baixo dos panos é equivalente a:
String nome2 = new String("Gabriel");

As duas formas funcionam, mas têm comportamentos diferentes — e já vou explicar o porquê.

Imutabilidade — o conceito mais importante

Se você for embora desse artigo lembrando de uma coisa só, que seja esta:

🚨 Strings em Java são IMUTÁVEIS.

O que isso significa? Imagina que você tem uma string "Goku". Quando você faz algo como:

String nome = "Goku";
nome = nome + " SSJ";
System.out.println(nome); // "Goku SSJ"

Parece que você “modificou” a string, né? Mentira. O que aconteceu de verdade foi:

  1. Java criou um novo objeto String com o valor "Goku SSJ".
  2. A variável nome agora aponta pra esse novo objeto.
  3. A string original "Goku" continua intacta na memória (até o garbage collector apagar, se ninguém mais usar).

Analogia rápida: pensa numa folha de papel onde você escreveu “Goku” a caneta. Você não pode apagar — só pode pegar uma folha nova, escrever “Goku SSJ” e jogar a antiga fora. É exatamente isso que o Java faz.

Por que isso importa?

Porque tem implicações reais:

String Pool — o “depósito secreto” do Java

Aqui vem uma sacada genial do Java pra economizar memória: o String Pool (ou string interning).

Quando você declara uma string usando literal (entre aspas), o Java guarda ela num “depósito” especial. Se você criar outra string com o mesmo valor, ele reaproveita a que já existe.

String a = "Goku";
String b = "Goku";

System.out.println(a == b); // true

Ué, == retornando true pra duas strings? Sim, porque na verdade a e b apontam pro mesmo objeto no pool. Java não criou dois objetos, criou um só.

Agora veja a diferença com new:

String a = "Goku";
String b = new String("Goku");

System.out.println(a == b);        // false → objetos diferentes!
System.out.println(a.equals(b));   // true  → mesmo conteúdo

Quando você usa new String(...), força a criação de um novo objeto no heap, fora do pool.

💡 Resumão pra gravar:

  • == compara referências (se é o mesmo objeto na memória).
  • .equals() compara conteúdo (se o texto é igual).
  • Pra String, use sempre .equals() quando quiser comparar valor.

Métodos que você vai usar TODO santo dia

A classe String tem dezenas de métodos. Não vou listar todos (se tiver essa curiosidade veja a documentação oficial), mas vou separar os que geralmente usamos:

Tamanho e verificação

String nome = "Goku";

nome.length();        // 4 — quantidade de caracteres
nome.isEmpty();       // false — verifica se é ""
nome.isBlank();       // false — verifica se é "" ou só espaços (Java 11+)

Comparação

"Goku".equals("Goku");              // true
"Goku".equalsIgnoreCase("goku");    // true — ignora maiúsculas/minúsculas
"Goku".compareTo("Vegeta");         // negativo (G vem antes de V no alfabeto)

Busca

String frase = "Goku é mais forte que Vegeta";

frase.contains("Vegeta");       // true
frase.startsWith("Goku");       // true
frase.endsWith("Vegeta");       // true
frase.indexOf("é");             // 5 — posição do primeiro 'é'
frase.indexOf("Yamcha");        // -1 — não encontrou

Manipulação (lembre: tudo retorna uma string NOVA!)

String nome = "  Goku  ";

nome.trim();           // "Goku" — remove espaços das pontas
nome.strip();          // "Goku" — versão moderna do trim (Java 11+)
nome.toUpperCase();    // "  GOKU  "
nome.toLowerCase();    // "  goku  "
nome.replace("o", "0"); // "  G0ku  "

"Goku,Vegeta,Gohan".split(","); // ["Goku", "Vegeta", "Gohan"]

Extração

String nome = "Dragon Ball Z";

nome.charAt(0);            // 'D' — caractere na posição
nome.substring(7);         // "Ball Z"
nome.substring(7, 11);     // "Ball"

Conversão pra String

String.valueOf(42);        // "42"
String.valueOf(true);      // "true"
Integer.toString(42);      // "42"

Concatenação — o vilão silencioso da performance

Olha esse código aparentemente inocente:

String resultado = "";
for (int i = 0; i < 10000; i++) {
    resultado += i + ",";
}

Esse trecho cria 10 mil objetos String ao longo do loop — porque cada += gera uma string nova. Em código grande, isso vira um problema sério de performance.

A solução: StringBuilder

Quando precisar construir strings dinamicamente, especialmente em loops, use o StringBuilder:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append(i).append(",");
}
String resultado = sb.toString();

StringBuilder é mutável — você vai alterando o mesmo objeto, sem criar lixo. Muito mais rápido.

💡 Existe também o StringBuffer, que é a versão thread-safe do StringBuilder. No dia a dia, prefira StringBuilder — só use StringBuffer se realmente precisar de segurança entre threads (raro hoje em dia).

Formatação — deixando suas strings bonitas

Em vez de ficar concatenando com +, use String.format() ou String.formatted() (Java 15+):

String nome = "Goku";
int forca = 9001;

// Forma clássica
String msg = String.format("O poder de %s é %d!", nome, forca);

// Forma moderna (Java 15+)
String msg2 = "O poder de %s é %d!".formatted(nome, forca);

System.out.println(msg); // "O poder de Goku é 9001!"

Principais marcadores:

Text Blocks — strings multilinha (Java 15+)

Antes, pra escrever uma string com várias linhas você sofria com \n e concatenação. Agora dá pra fazer assim:

String json = """
    {
        "nome": "Goku",
        "forca": 9001
    }
    """;

Muito mais legível! Excelente pra JSON, SQL, HTML, etc.

Pegadinhas comuns (cuidado!)

1) Comparar com ==

String a = new String("Goku");
String b = new String("Goku");
if (a == b) { ... } // false! Use .equals()

2) NullPointerException

String nome = null;
nome.length(); // NullPointerException

Use Objects.equals() ou compare invertido pra evitar:

"Goku".equals(nome); // seguro, mesmo se nome for null

3) Concatenação em loop Já comentei, mas vale repetir: use StringBuilder em loops.

4) split() com caracteres especiais O split() usa regex, então caracteres como ., |, * precisam ser escapados:

"192.168.0.1".split(".");      // retorna array vazio
"192.168.0.1".split("\\.");    // ["192", "168", "0", "1"]

Resumão

E aqui chegamos ao final de mais um artigo! String parece simples na superfície, mas tem muita coisa por baixo do capô. Depois que você entende imutabilidade e o pool, metade dos bugs somem.

Até a próxima! 🚀