StringBuffer x StringBuilder

ae pessoal queria saber qual a diferenca entre as duas classes… sei que a Stringbuilder não é segura em relação a threads segundo a kathy pois ainda nao estudei threads… mais a StringBuffer qual exatamente a diferença entre uma e outra?

É como a Kathy diz…

http://www.java-tips.org/java-se-tips/java.lang/difference-between-string-stringbuffer-and-stringbu.html

Camilo,

As duas classes têm o mesmo comportamento, a unica diferença mesmo é que a StringBuilder é Thread’s Safe, isso significa que se você vai utilizar um texto em uma unica Thread utilize StringBuilder, por não é sincronizada ela se torna mais rapida.

ta ai algo que eu queria ver. um benchmark no java 6 de stringbuilder e stringbuffer.

eu duvido muito que a velocidade seja muito diferente. alguem se habilita?

Legal você ter levantado isso!!

Não tenho muito experîência, e não encontrei nenhuma documentação sobre a performance das duas classes, mas encontrei alguns foruns sobre esse mesmo assunto:

http://forum.java.sun.com/thread.jspa?threadID=762884&messageID=4352865
http://forum.java.sun.com/thread.jspa?threadID=652378

A duvida permanece, mas parece que existe um ganho de performance… mesmo que minimo… E na duvida eu vou continuar usando a StringBuilder sempre que ela se mostrar viável…

[]'s

Adicionei uns 1000000 strings nas duas aqui e ambas levaram 297 milisegundos.

Ah, a VM é 1.6.0.

Como vc fez para conometrar o tempo?
Ate helloWord aqui em casa o tempo varia e segundos.
JDK 1.5.09
Netbeans 5.5

Passa o Codigo Mauricio

bom, eu li mais uma vez a parte q a kathy fala sobre isso… e achei a resposta… e vcs reforçaram valeu ai… e StringBuilder teoricamente é mais rapida por nao ser sincronizada em relação a Threads… mais eu usei as duas e nao percebi a diferença em questao de velocidade mais ja que eh recomendado a StringBuilder vou com ela… entao queria entender a essencia delas… mesmo… valeu galea :smiley: mais eu to usando o java 1.5…

Realmente, a diferença é pequena.

Via de regra, uso o StringBuilder. Dificilmente você vai usar o StringBuilder de maneira sincronizada, como seria o caso do StringBuffer. Mesmo em uma aplicação multi-thread, provavelmente o método que montará a string será sincronizado e será o único que usará o builder.

A sincronização realmente tem seu peso, mas nesse caso, esse peso será insignificante para a maior parte das aplicações.

E pessoal, cuidado com os micro-benchmarks. A JVM tem muitas otimizações que vão fazer códigos bem pequenos não terem diferença de tempo. Por exemplo, ela é capaz de perceber que um objeto gravado e não lido será descartado e eliminar completamente a sua criação. Um tema amplamente discutido é como fazer benchmark no java, mas algumas dicas podem ser encontradas em
http://www.javaperformancetuning.com/

Pessoal, fiz um humilde teste onde podemos ver que o uso da classe StringBuffer mostra uma grande diferença de tempo com relação a StringBuilder.

Obviamente que foi necessário utilizar Thread para que a diferença fosse notável.

Resultado aqui na minha máquina:

StringBuffer aprox. 1047ms.
StringBuilder aprox. 281ms.

Comentem e descomentem as linhas no inicio do código para alternar a execução do código entre StringBuffer e StringBuilder.
Não esqueçam de recomplilar! :stuck_out_tongue:

public class Tester implements Runnable {
    
    static StringBuffer buffer = new StringBuffer();
//    static StringBuilder buffer = new StringBuilder();
    
    
    public void run() {
        for (int i = 0; i &lt 1000000; i++) {
            buffer.append(getString());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Tester t = new Tester();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);

        long time = System.currentTimeMillis();
        t1.start();
        t2.start();

        while(t1.isAlive() || t2.isAlive() )
            Thread.sleep(1);
        
        System.out.println(System.currentTimeMillis() - time + "ms.");
    }
    
    public static String getString() {
        return "ABC"; 
    }
}

Testem aí… :thumbup:

Mas ai nao faz sentido, porque sua StringBuilder pode ficar com os caracteres em poscioes todas erradas, tamanho final da String errada, buracos no meio da String, etc

Sim, é verdade.
Mas onde está a diferença entre as classes? Justamente no fato de os métodos da StringBuffer serem synchronized, deste modo, somente fazendo uso da desvantagem de tempo que um método synchronized possui é que podemos ver alguma diferença de tempo. Será quer fora isso ainda existe outra coisa que pode resultar em diferença de performance?

[quote=rmarin]Sim, é verdade.
Mas onde está a diferença entre as classes? Justamente no fato de os métodos da StringBuffer serem synchronized, deste modo, somente fazendo uso da desvantagem de tempo que um método synchronized possui é que podemos ver alguma diferença de tempo. Será quer fora isso ainda existe outra coisa que pode resultar em diferença de performance?[/quote]

O que o Paulo disse é válido. Testando desse jeito não faz sentido. Se você tem mais de um thread acessando o StringBu* você vai ter que ou utilizar StringBuffer ou cuidar da sincronização você mesmo.

A questão aqui é que mesmo quando você só tem um thread acessando o StringBuffer a sincronização causa um overhead. E a pergunta é se esse overhead é significante ou não.

Prezado CamiloLopes

Seguem as teorias para ajudar em sua prática, espero ter contribuido.

Rodrigo

StringBuffer
Uma seqüência enfí-segura, mutable dos caráteres. Um amortecedor da corda é como uma corda, mas pode ser modificado. Em algum ponto a tempo contem alguma seqüência particular dos caráteres, mas o comprimento e o índice da seqüência podem ser mudados com determinadas chamadas do método. Os amortecedores da corda são seguros para o uso por linhas múltiplas. Os métodos são sincronizados onde necessário de modo que todas as operações em todo o exemplo particular se comportem como se ocorrem em alguma ordem de série que é consistente com a ordem das chamadas do método feitas por cada uma das linhas individuais envolvidas. As operações principais em um StringBuffer são a adição e introduzem os métodos, que são sobrecarregados para aceitar dados de qualquer tipo. Cada um converte eficazmente uma referência dada a uma corda e então adiciona ou introduz os caráteres dessa corda ao amortecedor da corda. O método da adição adiciona sempre estes caráteres na extremidade do amortecedor; o método da inserção adiciona os caráteres em um ponto especificado. Para o exemplo, se z consultasse a um objeto do amortecedor da corda cujos os índices atuais fossem “começo”, a seguir a chamada z.append(“le do método”) faria com que o amortecedor da corda contivesse “o startle”, visto que z.insert(4, “o le”) alterariam o amortecedor da corda para conter “o starlet”. No general, se o sb consultar a um exemplo de um StringBuffer, a seguir em sb.append(x) tem o mesmo efeito que sb.insert(sb.length(), x). Sempre que uma operação ocorre envolvendo uma seqüência da fonte (tal como a adição ou a introdução de uma seqüência da fonte) esta classe sincroniza somente no amortecedor da corda que executa a operação, não na fonte. Cada amortecedor da corda tem uma capacidade. Tão por muito tempo como o comprimento da seqüência do caráter contida no amortecedor da corda não excede a capacidade, não é necessário alocar uma disposição interna nova do amortecedor. Se o amortecedor interno transbordar, está feito automaticamente maior. Como de JDK 5 da liberação, esta classe foi suplementada com uma classe equivalente projetada para o uso por uma única linha, StringBuilder. A classe de StringBuilder deve geralmente ser usada na preferência a esta, porque suporta todas as mesmas operações mas é mais rápida, porque não executa nenhuma sincronização.

StringBuilder
Uma seqüência mutable dos caráteres. Esta classe fornece um API compatível com o StringBuffer, mas com nenhuma garantia da sincronização. Esta classe é projetada para o uso como a gota- na recolocação para StringBuffer nos lugares onde o amortecedor da corda era usado por uma única linha (como é geralmente o caso). Onde possível, se recomenda que esta classe esteja usada na preferência a StringBuffer porque será mais rápida sob a maioria de execuções. As operações principais em um StringBuilder são a adição e introduzem os métodos, que são sobrecarregados para aceitar dados de qualquer tipo. Cada um converte eficazmente uma referência dada a uma corda e então adiciona ou introduz os caráteres dessa corda ao construtor da corda. O método da adição adiciona sempre estes caráteres na extremidade do construtor; o método da inserção adiciona os caráteres em um ponto especificado. Para o exemplo, se z consultasse a um objeto do construtor da corda cujos os índices atuais fossem “começo”, a seguir a chamada z.append(“le do método”) faria com que o construtor da corda contivesse “o startle”, visto que z.insert(4, “o le”) alterariam o construtor da corda para conter “o starlet”. No general, se o sb consultar a um exemplo de um StringBuilder, a seguir em sb.append(x) tem o mesmo efeito que sb.insert(sb.length(), x). Cada construtor da corda tem uma capacidade. Tão por muito tempo como o comprimento da seqüência do caráter contida no construtor da corda não excede a capacidade, não é necessário alocar um amortecedor interno novo. Se o amortecedor interno transbordar, está feito automaticamente maior. Os exemplos de StringBuilder não são seguros para o uso por linhas múltiplas. Se tal sincronização for requerida então recomenda-se que StringBuffer esteja usado.

Segue ai pessoal, um exemplo pratico da diferença.

public class Main {
	public static void main(String[] args) {
		int N = 77777777;
		exemploComBuffer(N);
		exemploComBuilder(N);
	}

	private static void exemploComBuilder(int N) {
		long t = System.currentTimeMillis();
		StringBuilder sb = new StringBuilder();
		for (int i = N; i-- > 0;) {
			sb.append("");
		}
		System.out.println(System.currentTimeMillis() - t);
	}

	private static void exemploComBuffer(int N) {
		long t = System.currentTimeMillis();
		StringBuffer sb = new StringBuffer();
		for (int i = N; i-- > 0;) {
			sb.append("");
		}
		System.out.println(System.currentTimeMillis() - t);
	}
}