StringBuffer x StringBuilder

14 respostas
LPJava

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?

14 Respostas

paulorb.pacheco

É como a Kathy diz…

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

nicoweda

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.

Paulo_Silveira

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?

nicoweda

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

Mauricio_Linhares

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

Ah, a VM é 1.6.0.

A

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

LPJava

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…

ViniGodoy

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/

rmarin

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:

Paulo_Silveira

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

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?

Sami_Koivu

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?

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.

rodrigo_salla

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.

ednardoGuitar

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);
	}
}
Criado 20 de dezembro de 2006
Ultima resposta 7 de abr. de 2014
Respostas 14
Participantes 11