Java Essencial: Strings, imutabilidade e manipulação eficiente

Capítulo 11

Tempo estimado de leitura: 7 minutos

+ Exercício

String como objeto imutável

Em Java, String é um objeto que representa texto e é imutável: depois de criada, seu conteúdo não pode ser alterado. Quando você “muda” uma String, na verdade cria uma nova String e a variável passa a referenciar o novo objeto.

String s = "Java"; s = s + "!"; // cria um novo objeto "Java!"; o "Java" original permanece igual

Essa característica traz benefícios (segurança, previsibilidade, uso eficiente de memória em alguns cenários), mas também implica custo quando há muitas concatenações, especialmente em laços.

Imutabilidade na prática: o que acontece ao “alterar”

Considere uma limpeza de entrada:

String entrada = "  Ana  "; String limpa = entrada.trim(); // "Ana" (novo objeto) // entrada continua "  Ana  "

O método trim() não altera entrada; ele devolve outra String.

Comparação correta de Strings

Para comparar conteúdo de Strings, use equals (ou equalsIgnoreCase quando a diferença entre maiúsculas/minúsculas não importar). Evite usar == para comparar texto, pois == compara referências (se é o mesmo objeto), não o conteúdo.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

equals

String a = "java"; String b = "java"; boolean mesmoConteudo = a.equals(b); // true

equalsIgnoreCase

String comando = "SAIR"; if (comando.equalsIgnoreCase("sair")) { // ... }

Comparação segura contra null

Se há chance de a variável ser null, prefira chamar equals a partir de uma constante conhecida:

String status = null; boolean ok = "OK".equals(status); // false, sem NullPointerException

Métodos comuns para manipulação de texto

substring: recortar parte do texto

substring(inicio, fim) devolve uma nova String com caracteres do índice inicio (inclusivo) até fim (exclusivo). substring(inicio) vai até o final.

String cpf = "123.456.789-00"; String parte = cpf.substring(0, 3); // "123" String sufixo = cpf.substring(12); // "00"

Passo a passo prático (extraindo DDD de telefone):

  • 1) Garanta um formato esperado (ex.: (11) 99999-0000).
  • 2) Encontre os índices dos parênteses.
  • 3) Use substring para recortar.
String tel = "(11) 99999-0000"; int abre = tel.indexOf('('); int fecha = tel.indexOf(')'); String ddd = tel.substring(abre + 1, fecha); // "11"

indexOf: localizar caracteres ou trechos

indexOf retorna a posição da primeira ocorrência (ou -1 se não encontrar). Há variações com caractere, String e índice inicial.

String email = "ana.silva@empresa.com"; int arroba = email.indexOf('@'); // 9 String dominio = email.substring(arroba + 1); // "empresa.com"

Passo a passo prático (validando presença de separador):

  • 1) Procure o separador com indexOf.
  • 2) Se retornar -1, trate como formato inválido.
  • 3) Caso exista, recorte as partes com substring.
String linha = "produto=Teclado"; int pos = linha.indexOf('='); if (pos == -1) { throw new IllegalArgumentException("Linha inválida: " + linha); } String chave = linha.substring(0, pos); String valor = linha.substring(pos + 1);

split: quebrar texto em partes

split divide a String usando uma expressão regular. Para separadores simples como vírgula, funciona bem; para caracteres especiais de regex (como ., |, ?), é preciso escapar.

String csv = "Ana,Bruno,Caio"; String[] nomes = csv.split(","); // ["Ana", "Bruno", "Caio"]

Exemplo com ponto (precisa escapar):

String versao = "1.2.15"; String[] partes = versao.split("\\."); // ["1", "2", "15"]

Cuidados comuns:

  • Espaços ao redor: combine com trim() em cada parte.
  • Campos vazios: dependendo do caso, pode ser necessário tratar resultados vazios.

trim: remover espaços nas extremidades

trim() remove espaços (e alguns caracteres de controle) do início e do fim. É essencial para limpar entradas de usuário e dados vindos de arquivos.

String bruto = "   admin  "; String usuario = bruto.trim(); // "admin"

Passo a passo prático (limpeza de lista separada por vírgula):

String entrada = "  Ana ,  Bruno, Caio  "; String[] itens = entrada.split(","); for (int i = 0; i < itens.length; i++) { itens[i] = itens[i].trim(); } // itens: ["Ana", "Bruno", "Caio"]

Formatação de texto com String.format

String.format cria Strings formatadas com placeholders. É útil para mensagens padronizadas, relatórios simples e logs legíveis.

Placeholders comuns

  • %s: texto
  • %d: inteiro
  • %.2f: decimal com 2 casas
  • %n: quebra de linha independente do sistema (use quando precisar de múltiplas linhas)
String nome = "Ana"; int itens = 3; double total = 59.9; String msg = String.format("Olá, %s! Você tem %d itens. Total: R$ %.2f", nome, itens, total);

Passo a passo prático (mensagem de cobrança):

  • 1) Tenha os dados já em tipos corretos (ex.: int, double).
  • 2) Defina o template com placeholders.
  • 3) Gere a mensagem com String.format.
int numeroPedido = 1024; String cliente = "Bruno"; double valor = 120.0; String texto = String.format("Pedido #%d | Cliente: %s | Valor: R$ %.2f", numeroPedido, cliente, valor);

Concatenação e custo em laços: por que StringBuilder existe

Como String é imutável, cada concatenação pode criar um novo objeto. Em laços, isso pode gerar muitas alocações e cópias de caracteres, aumentando tempo e uso de memória.

Exemplo de concatenação repetida (evitar em laços grandes)

String resultado = ""; for (int i = 1; i <= 5; i++) { resultado = resultado + i + ","; } // cria várias Strings intermediárias

StringBuilder: concatenação eficiente

StringBuilder é um objeto mutável para montar texto. Você adiciona partes com append e, ao final, chama toString() para obter uma String.

StringBuilder sb = new StringBuilder(); for (int i = 1; i <= 5; i++) { sb.append(i).append(','); } String resultado = sb.toString();

Passo a passo prático (gerar lista com separador sem vírgula final):

  • 1) Crie um StringBuilder.
  • 2) Para cada item, adicione o separador apenas se não for o primeiro.
  • 3) Converta para String no final.
String[] nomes = {"Ana", "Bruno", "Caio"}; StringBuilder sb = new StringBuilder(); for (int i = 0; i < nomes.length; i++) { if (i > 0) sb.append(" | "); sb.append(nomes[i]); } String saida = sb.toString(); // "Ana | Bruno | Caio"

Exercícios práticos (parsing, limpeza e mensagens formatadas)

1) Parsing de linha chave=valor

Objetivo: Dada uma linha como "produto=Teclado", extrair chave e valor, removendo espaços extras.

Requisitos: usar indexOf, substring e trim.

// Entrada: "  produto = Teclado Mecânico  " // Saída esperada: chave="produto", valor="Teclado Mecânico"

Dicas:

  • Use indexOf('=') e valide -1.
  • Recorte com substring e aplique trim() em ambos.

2) Limpeza de lista de e-mails separados por ponto e vírgula

Objetivo: Transformar " ana@x.com ; BRUNO@y.com; caio@z.com " em uma lista normalizada (sem espaços e com domínio/usuário preservados), e contar quantos são do domínio y.com ignorando maiúsculas/minúsculas.

Requisitos: usar split, trim, equalsIgnoreCase, indexOf e substring.

// Sugestão de passos: // 1) split(";") // 2) trim() em cada item // 3) pegar domínio: substring(email.indexOf('@') + 1) // 4) comparar domínio com equalsIgnoreCase("y.com")

3) Gerar mensagem formatada a partir de dados CSV

Objetivo: Dada uma linha CSV "Ana,3,59.90" (nome, quantidade, total), gerar: "Cliente: Ana | Itens: 3 | Total: R$ 59.90".

Requisitos: usar split, trim e String.format.

// Entrada: "Ana,3,59.90" // Saída: "Cliente: Ana | Itens: 3 | Total: R$ 59.90"

Dicas:

  • Após split, aplique trim() nos campos.
  • Converta quantidade para inteiro e total para decimal conforme sua necessidade.
  • Use String.format("Cliente: %s | Itens: %d | Total: R$ %.2f", ...).

4) Montar relatório com StringBuilder

Objetivo: A partir de um array de linhas "nome: Ana", "nome: Bruno", gerar um relatório com numeração, usando StringBuilder para eficiência.

Requisitos: usar StringBuilder, append, indexOf e substring.

// Entradas: ["nome: Ana", "nome: Bruno"] // Saída: "1) Ana\n2) Bruno\n" (use %n se optar por String.format)

Dicas:

  • Encontre o : com indexOf e recorte o valor com substring(pos + 1).trim().
  • Use sb.append(i + 1).append(") ").append(nome).append(System.lineSeparator());.

Agora responda o exercício sobre o conteúdo:

Ao comparar o conteúdo de Strings em Java, qual abordagem é mais adequada quando a variável pode ser null, evitando NullPointerException?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Para comparar conteúdo com segurança quando a variável pode ser null, chame equals na constante (ex.: "OK".equals(status)). Assim, não há chamada de método em uma referência nula.

Próximo capitúlo

Java Essencial: Arrays e algoritmos básicos de manipulação

Arrow Right Icon
Capa do Ebook gratuito Java Essencial: Fundamentos da Linguagem e do Ecossistema (JDK, IDE, Maven)
61%

Java Essencial: Fundamentos da Linguagem e do Ecossistema (JDK, IDE, Maven)

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.