Entendendo as classes String, StringBuilder e StringBuffer.


   Fala galera! Vocês já pararam pra pensar em como as strings funcionam em Java? Pois é, um amigo meu resolveu parar essa semana e acabou se confundindo mais do que se explicando. Como a conversa com ele rendeu bastante, achei interessante escrever um artigo que aborda este assunto que pode lhe surpreender se você ainda não conhece a linguagem Java mais profundamente.
   A classe String representa um conjunto de caracteres Unicode, cada um contendo 16 bits (curiosidade: um char não possui bit de sinal [negativo ou positivo], então, 8 bits são para armazenar valor [(2 elevado a 8) – 1 que é igual a 255 {-1 pois o zero é considerado um inteiro positivo} caracteres {que utilizamos no teclado}] e mais 8 bits para internacionalização, dando suporte assim, a diversos idiomas e a meros 65535 caracteres diferentes). Ela é declarada como final e, portanto não pode ser estendida. Isto preserva este tipo de dado, reforçando sua imutabilidade e assegurando que uma String sempre será uma String (eles decidiram que você não pode herdar de char, nem de double e nem de String, além de diversas outras).
   A primeira coisa que temos que entender é que a classe String é imutável. Mas como assim imutável? É exatamente o que a palavra diz. Imutável, isto é, não muda, seu estado é único e imodificável. Quando criamos um objeto do tipo String, estamos na verdade criando um objeto que jamais terá seu valor modificado, porém, sua referência pode ser compartilhada com demais variáveis. Assim, podemos passar este valor único e imutável de nossa string criada para diversas outras variáveis de referência a strings. Para entendermos melhor, vamos começar com um simples exemplo:

String str = new String(); // String vazia.

   Aqui, declaramos e inicializamos uma string vazia, ou seja, "", e atribuímos este valor a uma variável de referência a strings chamada str. Mas existe uma maneira mais prática e não redundante de se inicializar um objeto String. Você poderia fazer simplesmente

String str = ""; // String vazia.

   Considerando que as duas linhas apresentadas acima representem apenas uma linha (desconsidere uma delas), observe o trecho a seguir:

str += "minha String"; // É igual: String str = str + "minha String";

   Agora str é um "ponteiro" para "minha string". Se criássemos outra variável chamada outraStr e fizéssemos

String outraStr = str;

outraStr então referenciaria também o objeto "minha String". Mas e nossa string vazia criada anteriormente? Ela não é imutável? Então como modifiquei seu valor para "minha String" com concatenação?

str += " imutável"; // O valor de str agora é "minha String imutável".

   É aqui onde mora o segredo. O objeto antigo de str ("minha String", isto mesmo, str agora referência outro objeto) foi simplesmente abandonado. Como a string é única, este tipo de concatenação "joga fora" o objeto antigo e cria um novo objeto (neste caso, "minha String imutável") com a nova string. Assim se nós não tivéssemos criado a variável outraString para armazenar o caminho da antiga string, esta estaria perdida na memória e seria irrecuperável.
   Aqui vai um pequeno desafio. Você conseguiria me dizer quantos objetos do tipo String foram criados no código abaixo?

String str1 = "minha String ";
String str2 = str1.concat("imutável ");
str1.concat(" teste");
str2.concat("imutável ");
str2 = "ok";
str2.toUpperCase();

Cria o objeto "minha String ".
str1 aponta para "minha String ".
Cria o objeto "imutável " (perdido na memória).
Cria o objeto "minha String imutável ".
str2 aponta para "minha String imutável ".
Cria o objeto " teste" (perdido na memória).
Cria o objeto "minha String teste" (perdido na memória, pois, nenhuma variável recebe o retorno de str1.concat(" teste");).
Tenta criar "imutável ", mas, consta que esta já existe no pool constante de Strings, isto é, já foi criado antes. Assim, reutiliza o objeto "imutável " criado anteriormente.
Cria o objeto "minha String imutável imutável " (perdido na memória).
Cria o objeto "ok".
str2 aponta para "ok".
"minha String imutável " (antigamente referenciada por str2) se perde na memória.
Cria o objeto "OK" (perdido na memória) e str2 ainda referência "ok".

Resposta: 8.

   Vale lembrar também que anteriormente declaramos

String str = new String();

e

String str = "minha String";

   Apenas lembre-se de que toda vez que utilizar o operador new, um novo objeto estará sendo criado. Portanto, na primeira linha criamos dois objetos e uma referência enquanto na segunda criamos apenas um objeto e uma referência.

Classes mutáveis: StringBuilder e StringBuffer.

   Antes de tudo lembre-se disto: StringBuilder é equivalente a StringBuffer porém, StringBuffer é sincronizado enquanto StringBuilder não. Assim, StringBuilder é mais eficiente que StringBuffer e deve ser usado sempre que possível, a não ser que você esteja escrevendo um programa multi-thread. Por instância, estarei pronunciando apenas StringBuilder, mas o mesmo também é válido para a classe StringBuffer.
   A grande diferença entre strings comuns e string builders é a mutabilidade. Com StringBuilder, você cria apenas um objeto para manipulação de strings ao invés de criar diversos como no exemplo mostrado acima. Considere o exemplo:

StringBuilder strBuilder = new StringBuilder("Um");
strBuilder.append(" valor!");
System.out.println(strBuilder); // Saída: Um valor!.

   Como você pode ver, StringBuilder opera em seu próprio valor, evitando a criação de diversos objetos indesejados. Ela fornece uma interface fácil e de rápido aprendizado, assim você pode tranquilamente modificar os valores da string dentro do objeto em questão. Note que o cast do tipo StringBuilder para o tipo String na terceira linha é feito automaticamente. Isso nem sempre poderá ser feito, por isto o método toString() também estará disponível para você.
   Notou como pode ser perigoso trabalhar com strings em Java? Imagine-se desenvolvendo um aplicativo com grande volume de entrada e saída de dados, concatenação, escrita em arquivos e etcetera. Você precisa se assegurar, não só neste caso, mas sempre, de que suas técnicas de programação sempre estarão atualizadas e eficientes. Só assim você conseguirá escrever código com qualidade de verdade. Um grande abraço e até a próxima!

This entry was posted in Java. Bookmark the permalink.

Leave a comment