String, StringBuilder e StringBuffer

Salve computêros, depois de muita espera de meu amigo Lucas, pelo meu post sobre Strings, cá estou eu para falar um pouco sobre 3 tipos de Strings e como usa-las.Primeiramente temos nossa velha e boa String, em Java as Strings são objetos, que podem ser criadas de diversas formas,por exemplo:

String s = new String ();
s = "String";

String s = new String ("String");

String s = "String";

Os objetos de tipo String podem parecer apenas objetos como outros qualquer, porém há uma diferença, muito significativa para as Strings, elas são imutáveis,isso mesmo meu caro imutáveis, ou seja o valor de uma String não podem ser modificado, apenas referenciado,seguimos um exemplo:

String s = "Comput";
s.concat("ero");
System.out.println("x = " + s); //resultado s = Comput

Agora eu peguei vocês neh?! Pois então, vocês esperavam que a saida nos trouxesse Computero, porém como já havia dito, as Strings são imutáveis,então o objeto referenciado por s não modificou seu valor.
Agora vejamos um outros exemplo:

String s = "Comput";
s = s.concat("ero");
System.out.println("x = " + x); //resultado x = Computero

Agora confudiu tudo neh?! Vamos lá, o que acontece agora é que ao dizer que s = s.concat(“ero”); um novo objeto Computero foi criado na memoria, concatenando o valor de s com o “ero”, e então atribuimos a variavel s o novo objeto criado.

Bom agora vamos pensar um pouquinho, já que foi criado um novo objeto com o valor “Computero”, vocês devem estar se perguntando o que é que acontece com aquele velho objeto “Comput”?
Existe um local da memoria chamado “String constant pool“, este é o lugar onde se encontra nosso velho valor “Comput”. “String constant pool” é um eficiente gerenciador de memoria em java.Basicamente todos os objetos são manejados na area HEAP da memoria, exceto Strings.Na maioria das aplicações, programadores usam o objeto String muitas vezes, e este objeto é frequentemente alterado ou ocupa muito espaço na memória.Então, ao invés de usarem a area HEAP da memória, criaram “String constant pool“. A vantagem de ter esta “String constant pool” é que ela não cria um objeto String se o mesmo já existir na “String constant pool“.

Exemplo:

String var1 = "Computero";
String var2 = "Computero";

Para os dois objetos, a JVM vai criar apenas um objeto na “String constant pool” e o segundo vai apenas referenciar.

Um grande problemas disso tudo, é que acabamos sempre com a memória cada vez maior, e varios objetos perdidos na memória.Para salvar este grande problema entre as Strings, foram criadas outras duas classes, a StringBuilder e a StringBuffer, veremos adiante a diferença entre elas.
Primeiramente a diferença entre a StringBuilder e a StringBuffer é que na StringBuffer os métodos são sincronizados, ou seja, é acessado apenas uma Thread por vez. A sincronização afeta diretamente o desempenho, portanto, a StringBuffer tende a ser mais lenta que a Builder.

Porque usar StringBuilder ou StringBuffer?
Estas classes são usadas normalmente quando precisamos manipular muitas strings, porém não podemos deixar objetos perdidos na memória, de forma que em alguns minutos ela estoura.
Um exemplo de StringBuilder, vamos lá:

StringBuilder sb = new StringBuilder();
sb.append("Comput");
sb.append("ero");
system.out.println("x = " + sb);//x = Computero

O que acontece é o seguinte, a StringBuilder ou StringBuffer vai operar sobre o valor do objeto que chamou o metodo append, coisa que a String não faz quando chamamos o metodo concat, vendo que ela necessida de um novo objeto para concatenar.
O mais maravilhoso desse metodo append é que ele vai aceitar concatenar o que você necessitar, seja ele um int, um char, um double ou até mesmo um float.
Vejamos alguns métodos destas maravilhosas classes:

Reverse() – imprime de forma contrária
Insert() – insere algo na posição especificada
Delete() – deleta algo na posição início e fim.

Mais alguns exemplos usando estes metodos :

//usando o metodo reverse da classe StringBuffer

public class Reverse {

public static void main(String args[]){
StringBuilder sb = new StringBuilder();
sb.append("Computero");//concatenando String
sb.append(2009);//concatenando int
sb.append('H');//concatenando char
System.out.println(sb);//imprimindo sb - Computero2009H
System.out.println(sb.reverse());//imprimindo de forma reversa sb - H9002oretupmoC
}
}
//exemplo usando alguns metodos da classe StringBuilder

public class Reverse {
public static void main(String[] args) {
StringBuilder sb= new StringBuilder("Computero");

/*metodo que remove pelo indice a partir do indice 6 (conta com ele) até o indice 9(não conta com ele)*/
sb.delete(6, 9);
/*imprimi Comput*/
System.out.println(sb);
/*concatena - a String portanto sb esta valendo Comput-*/
sb.append("-");
/*insere na posição 7 a palavra Jaqueline*/
sb.insert(7,"Jaqueline");
//imprimi Comput-Jaqueline
System.out.println(sb);
/*concatena -Bento a String portanto sb esta valendo Comput-Jaqueline-Bento*/
sb.append("-Bento");
/*imprimi Comput-Jaqueline-Bento*/
System.out.println(sb.toString());
}}/*a vantagem de usar StringBuilder ou StringBuffer é que nao tenho objetos perdidos na minha memória*/

Então é isso Computeros, espero ter ajudado em algo ou esclarecido alguma duvida.
Obrigada pelo espaço Lucas.
Boa tarde.