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,
Stringnã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:
- Java criou um novo objeto String com o valor
"Goku SSJ". - A variável
nomeagora aponta pra esse novo objeto. - 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:
- Performance: concatenar string num loop é caro, porque cada
+=cria um objeto novo. - Segurança: strings imutáveis são thread-safe por natureza.
- Hash estável: isso permite que Strings sejam ótimas chaves em
HashMap.
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 doStringBuilder. No dia a dia, prefiraStringBuilder— só useStringBufferse 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:
%s→ string%d→ inteiro%f→ float/double%.2f→ float com 2 casas decimais%n→ quebra de linha
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
- String é objeto, não primitivo.
- Imutável — toda “alteração” cria uma string nova.
- O String Pool reaproveita literais iguais pra economizar memória.
- Compare strings com
.equals(), nunca com==. - Pra construir strings em loops, use
StringBuilder. - Pra formatar, use
String.format()ou.formatted(). - Pra strings multilinha, use text blocks (
"""). - Cuidado com
nulle com regex nosplit().
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! 🚀