W3docs

Classe String do Java

Uma análise mais profunda da classe String do Java — seu design, estrutura interna e métodos principais.

String é o tipo de referência mais utilizado em Java, de longe. Você o encontrou no primeiro dia — String name = "Ada"; — e ele se inseriu no seu código sem muito alarde. Esta parte do livro vai a fundo por baixo dessa superfície. A classe tem mais profundidade do que aparenta: um layout interno fixo, sintaxe específica da linguagem que outros tipos não possuem, um pool de memória que afeta a identidade, e uma escolha de design deliberada (imutabilidade) que reverbera em threading, hashing e segurança.

Este capítulo é o mapa. O restante da Parte 9 preenche cada região.

O que é uma String?

Uma String é um objeto Java comum — java.lang.String, no mesmo pacote que Object e Integer. É final, portanto não pode ser subclassificada, e todo método que "modifica" uma string na verdade retorna uma nova. O original nunca é alterado.

String greeting = "hello";
greeting.toUpperCase();          // returns "HELLO" — discarded
System.out.println(greeting);    // still prints "hello"
greeting = greeting.toUpperCase();
System.out.println(greeting);    // now prints "HELLO"

Esse hábito de retornar-uma-nova é o fato mais importante sobre a classe. Ele é abordado em profundidade em Imutabilidade da String em Java.

Tratamento no nível da linguagem

Duas partes da sintaxe são reservadas para String e não são extensíveis a outros tipos:

  • Literais de string"hello" produz um objeto String diretamente, sem new. O compilador também deduplica literais idênticos no pool de strings.
  • O operador + — sobrecarregado para strings: "a" + "b" é "ab". Até expressões mistas como "score: " + 42 funcionam, pois o Java converte o lado direito para uma String.

Por trás das cenas, compiladores Java modernos traduzem cadeias de + usando StringBuilder ou o StringConcatFactory baseado em invokedynamic, portanto raramente você precisa escrever a concatenação manualmente. O compilador sabe o que fazer.

Layout interno

Antes do Java 9, cada String armazenava um char[] — dois bytes por caractere independentemente do conteúdo. O Java 9 introduziu compact strings: o array de apoio agora é um byte[], mais um campo coder de um byte que registra se os bytes são Latin-1 (um byte por caractere) ou UTF-16 (dois bytes). Para texto que cabe em Latin-1 — a maior parte do código, configuração, identificadores, inglês simples — isso reduz aproximadamente pela metade o consumo de memória sem alterar a API.

Você não pode ver o campo, não pode alterá-lo, não precisa pensar sobre ele. Mas é por isso que programas com uso intensivo de strings no JDK 9+ usam consideravelmente menos heap do que usavam no JDK 8.

As famílias de métodos principais

A API de String é grande, mas se organiza em alguns grupos reconhecíveis:

Inspeção. length(), isEmpty(), isBlank(), charAt(i), codePointAt(i), hashCode().

Busca. indexOf, lastIndexOf, contains, startsWith, endsWith, matches.

Extração. substring(start), substring(start, end), chars(), codePoints(), toCharArray().

Transformação. toUpperCase(), toLowerCase(), trim(), strip(), replace, replaceAll, replaceFirst, concat.

Divisão e junção. split, String.join — abordados em split() e join().

Formatação. String.format, o método de instância formatted e saída no estilo printf — abordados em Formatação de strings.

Comparação. equals, equalsIgnoreCase, compareTo, compareToIgnoreCase, contentEquals — abordados em Comparação de strings.

Conversão. valueOf (estático), toString (instância), helpers de parsing em Integer, Double, etc. — abordados em Conversões de strings.

Listagens completas da API estão no Javadoc do JDK. A habilidade está em reconhecer qual família usar, não em memorizar cada sobrecarga.

Strings são sequências de unidades de código UTF-16

charAt(i) e length() contam unidades de código UTF-16, não caracteres Unicode. Para texto dentro do Plano Multilíngue Básico (a maior parte dos scripts comuns), um char = um caractere e a distinção nunca importa. Para caracteres suplementares — a maioria dos emojis, algumas extensões CJK, scripts antigos — um único caractere visível ao usuário ocupa dois chars, um par substituto.

String emoji = "🙂";
System.out.println(emoji.length());          // 2 — two code units
System.out.println(emoji.codePointCount(0, emoji.length())); // 1 — one code point

Se você precisar iterar por ponto de código Unicode, use codePoints() ou codePointAt. Para a maioria dos casos de uso semelhantes ao ASCII — dividir CSVs, formatar linhas de log, comparar identificadores — length() e charAt são exatamente o que você quer.

Primos mutáveis: StringBuilder e StringBuffer

Quando você precisa construir uma string pedaço por pedaço, o uso repetido de += aloca uma nova String a cada passo. A biblioteca padrão fornece dois companheiros mutáveis para esse caso:

  • StringBuilder — rápido, single-threaded.
  • StringBuffer — mesma API, métodos sincronizados, útil apenas quando mais de uma thread escreve no mesmo buffer.

Eles têm APIs paralelas e capítulos paralelos nesta parte do livro.

Um exemplo prático

Um pequeno exercício que toca nas famílias mais comuns — inspeção, busca, extração, transformação e conversão — na mesma entrada. Leia a saída linha por linha; cada chamada ilustra uma ferramenta da lista acima.

java— editable, runs on the server

A última linha é a conclusão. Após cada transformação que usamos, line em si é byte-idêntica ao literal com o qual começamos — prova de que o modelo de retornar-uma-nova é real, não apenas uma nota de documentação.

O que vem a seguir

Strings vêm com um modelo de memória único na biblioteca padrão: literais idênticos compartilham armazenamento, e você pode optar por inserir strings arbitrárias nesse pool compartilhado com uma única chamada de método. Continue para Pool de Strings do Java.

Prática

Prática
Qual afirmação sobre a classe `String` do Java é verdadeira?
Qual afirmação sobre a classe `String` do Java é verdadeira?
Was this page helpful?