it-swarm-pt.tech

Por que usar StringBuffer em Java em vez do operador de concatenação de string

Alguém me disse que é mais eficiente usar StringBuffer para concatenar strings em Java do que usar o + operador para Strings. O que acontece quando você faz isso? O que StringBuffer faz diferente?

54
harry

É melhor usar o StringBuilder (é uma versão não sincronizada; quando você constrói seqüências em paralelo?) Atualmente, em quase todos os casos, mas eis o que acontece:

Quando você usa + com duas strings, ele compila código como este:

String third = first + second;

Para algo assim:

StringBuilder builder = new StringBuilder( first );
builder.append( second );
third = builder.toString();

Portanto, para apenas pequenos exemplos, geralmente não faz diferença. Mas quando você está construindo uma cadeia complexa, geralmente tem muito mais com o que lidar; por exemplo, você pode estar usando muitas instruções anexas diferentes ou um loop como este:

for( String str : strings ) {
  out += str;
}

Nesse caso, uma nova instância StringBuilder e uma nova String (o novo valor de out - Strings são imutáveis) é necessária em cada iteração. Isso é muito inútil. Substituir isso por um único StringBuilder significa que você pode produzir um único String e não preencher o monte com Strings dos quais você não se importa.

62
Calum

Para concatenações simples como:

String s = "a" + "b" + "c";

É um pouco inútil usar StringBuffer - como jodonnell apontou que será traduzido de forma inteligente em:

String s = new StringBuffer().append("a").append("b").append("c").toString();

MAS não é muito bom concatenar seqüências de caracteres em um loop, como:

String s = "";
for (int i = 0; i < 10; i++) {
    s = s + Integer.toString(i);
}

O uso de string neste loop gera 10 objetos de string intermediários na memória: "0", "01", "012" e assim por diante. Ao escrever o mesmo usando StringBuffer, você simplesmente atualiza um buffer interno de StringBuffer e não cria os objetos de cadeia intermediária dos quais não precisa:

StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
    sb.append(i);
}

Na verdade, para o exemplo acima, você deve usar StringBuilder (introduzido em Java 1.5)) em vez de StringBuffer - StringBuffer é um pouco mais pesado, pois todos os seus métodos são sincronizados.

42
tkokoszka

Um não deve ser mais rápido que o outro. Isso não era verdade antes Java 1.4.2, porque ao concatenar mais de duas cadeias usando o operador "+"), objetos intermediários String seriam criados durante o processo de construção a corda final.

No entanto, como o JavaDoc para StringBuffer afirma, pelo menos desde Java 1.4.2 usando o operador "+" compila para criar um StringBuffer e append() in the many strings to it.Então, aparentemente, não há diferença.

No entanto, tenha cuidado ao adicionar uma string a outra dentro de um loop! Por exemplo:

String myString = "";

for (String s : listOfStrings) {
  // Be careful! You're creating one intermediate String object
  // for every iteration on the list (this is costly!)
  myString += s;
}

No entanto, lembre-se de que geralmente concatenar algumas seqüências de caracteres com "+" é mais limpo que append() _ todas elas.

20
André Chalella

Sob o capô, ele realmente cria e anexa a um StringBuffer, chamando toString () no resultado. Então, na verdade, não importa mais o que você usa.

Tão

String s = "a" + "b" + "c";

torna-se

String s = new StringBuffer().append("a").append("b").append("c").toString();

Isso é verdade para vários anexos incorporados em uma única declaração. Se você criar sua string ao longo de várias instruções, estará desperdiçando memória e um StringBuffer ou StringBuilder é sua melhor escolha.

9
jodonnell

Eu acho que dado o jdk1.5 (ou superior) e sua concatenação é segura para threads, você deve usar StringBuilder em vez de StringBuffer http://Java4ever.blogspot.com/2007/03/string-vs-stringbuffer-vs -stringbuilder.html Quanto aos ganhos de velocidade: http://www.about280.com/stringtest.html

Pessoalmente, eu codificaria a legibilidade, portanto, a menos que você ache que a concatenação de strings torna seu código consideravelmente mais lento, fique com o método que for mais legível.

7
slipset

Em alguns casos, isso é obsoleto devido às otimizações executadas pelo compilador, mas o problema geral é esse código como:

string myString="";
for(int i=0;i<x;i++)
{
    myString += "x";
}

atuará como abaixo (cada etapa é a próxima iteração do loop):

  1. construa um objeto de cadeia de comprimento 1 e valor "x"
  2. Crie um novo objeto de string do tamanho 2, copie a string antiga "x" para ele e adicione "x" na posição 2.
  3. Crie um novo objeto de string 3, copie a string antiga "xx" e adicione "x" na posição 3.
  4. ... e assim por diante

Como você pode ver, cada iteração precisa copiar mais um caractere, resultando em operações 1 + 2 + 3 + 4 + 5 + ... + N em cada loop. Esta é uma operação O (n ^ 2). Se, no entanto, soubéssemos antecipadamente que só precisávamos de N caracteres, poderíamos fazê-lo em uma única alocação, com cópia de apenas N caracteres das strings que estávamos usando - um mero O(n) Operação.

O StringBuffer/StringBuilder evita isso porque eles são mutáveis ​​e, portanto, não precisam continuar copiando os mesmos dados repetidamente (desde que haja espaço para copiar no buffer interno). Eles evitam executar uma alocação e copiam proporcionalmente ao número de anexos feitos, alocando demais o buffer por uma proporção do seu tamanho atual, fornecendo amortizado O(1) anexado.

No entanto, vale a pena notar que, muitas vezes, o compilador será capaz de otimizar o código no estilo StringBuilder (ou melhor - já que ele pode executar dobragens constantes etc.) automaticamente.

5
Brian

AFAIK, depende da versão da JVM, nas versões anteriores à 1.5, usando "+" ou "+ =", na verdade, copiava toda a cadeia de caracteres toda vez.

Cuidado ao usar + = na verdade aloca a nova cópia da string.

Como foi apontado, usar + nos loops envolve copiar.

Quando cadeias que são conactenadas são constantes de tempo de compilação, concatenadas em tempo de compilação, então

String foo = "a" + "b" + "c";

Has é compilado para:

String foo = "abc"; 
3
jb.

Java transforma string1 + string2 em uma construção StringBuffer, append () e toString (). Isso faz sentido.

No entanto, em Java 1.4 e anterior, isso seria feito para o operador each + na instrução separadamente. Isso significava que fazer um + b + c resultaria em dois StringBuffer constrói com dois toString () chamadas. Se você tivesse uma longa sequência de concats, isso se tornaria uma verdadeira bagunça. significava que você poderia controlar isso e fazê-lo corretamente.

O Java 5.0 e superior parecem fazê-lo de forma mais sensata, por isso é menos problemático e certamente menos detalhado.

3
Alan Krueger

Outras informações:

StringBuffer é uma classe segura para threads


public final class StringBuffer extends AbstractStringBuilder
    implements Serializable, CharSequence
{
// .. skip ..
     public synchronized StringBuffer append(StringBuffer stringbuffer)
    {
        super.append(stringbuffer);
        return this;
    }
// .. skip ..
}

Mas o StringBuilder não é seguro para threads, portanto, é mais rápido usar o StringBuilder, se possível


public final class StringBuilder extends AbstractStringBuilder
    implements Serializable, CharSequence
{
// .. skip ..
    public StringBuilder append(String s)
    {
        super.append(s);
        return this;
    }
// .. skip ..
}

1
Eric Yung

StringBuffer é mutável. Ele adiciona o valor da string ao objeto mesmo sem instanciar outro objeto. Fazendo algo como:

myString = myString + "XYZ"

criará um objeto novo String.

1
Loren Segal

Para concatenar duas cadeias usando '+', uma nova cadeia precisa ser alocada com espaço para as duas cadeias e, em seguida, os dados copiados das duas cadeias. Um StringBuffer é otimizado para concatenar e aloca mais espaço do que o necessário inicialmente. Quando você concatena uma nova sequência, na maioria dos casos, os caracteres podem ser simplesmente copiados para o final do buffer existente.
Para concatenar duas cadeias, o operador '+' provavelmente terá menos sobrecarga, mas à medida que você concatena mais cadeias, o StringBuffer se destaca, usando menos alocações de memória e menos cópia de dados.

1
Eclipse

A classe StringBuffer mantém uma matriz de caracteres para armazenar o conteúdo das seqüências concatenadas, enquanto o método + cria uma nova sequência sempre que é chamado e anexa os dois parâmetros (param1 + param2).

O StringBuffer é mais rápido porque 1. pode ser capaz de usar sua matriz já existente para concat/armazenar todas as cadeias. 2. mesmo que não se encaixem na matriz, é mais rápido alocar uma matriz de apoio maior do que gerar novos objetos String para cada evocação.

1
Matt Novinger

Como as Strings são imutáveis, cada chamada para o operador + cria um novo objeto String e copia os dados da String para a nova String. Como copiar uma String leva um tempo linear no comprimento da String, uma sequência de N chamadas para o operador + resulta em O (N2) tempo de execução (quadrático).

Por outro lado, como um StringBuffer é mutável, ele não precisa copiar a String toda vez que você executa um Append (), portanto, uma sequência de chamadas N Append () leva O(N) time ( Isso só faz uma diferença significativa no tempo de execução se você estiver anexando um grande número de Strings.

1
Adam Rosenfield

Como dito, o objeto String é inmutável, ou seja, uma vez criado (veja abaixo), ele não pode ser alterado.

String x = new String ("alguma coisa"); // ou

String x = "alguma coisa";

Portanto, quando você tenta concanar objetos String, o valor desses objetos é obtido e colocado em um novo objeto String.

Se você usar o StringBuffer, que IS mutável, você adiciona continuamente os valores a uma lista interna de caracteres (primitivos), que pode ser estendida ou truncada para ajustar o valor necessário. são criados, apenas novos caracteres são criados/removidos quando necessário para manter os valores.

1
Christian P.

Ao concatenar duas cadeias, você realmente cria um terceiro objeto String em Java. O uso de StringBuffer (ou StringBuilder em Java 5/6)) é mais rápido porque ele usa uma matriz interna de caracteres para armazenar a string e quando você usa um dos métodos add (...) , ele não cria um novo objeto String. Em vez disso, StringBuffer/Buider acrescenta a matriz interna.

Em concatenações simples, não é realmente um problema concatenar cadeias usando StringBuffer/Builder ou o operador '+', mas ao fazer muitas concatenações de cadeias, você verá que usar um StringBuffer/Builder é muito mais rápido.

1
Alexandre Brasil

Como Strings são imutáveis ​​em Java, toda vez que você concana uma String, um novo objeto é criado na memória. StringBuffer usa o mesmo objeto na memória.

0
Ivan Bosnic

Eu acho que a resposta mais simples é: é mais rápido.

Se você realmente quer conhecer todas as coisas secretas, sempre pode dar uma olhada na fonte:

http://www.Sun.com/software/opensource/Java/getinvolved.jsp

http://download.Java.net/jdk6/latest/archive/

0
rgcb

A seção Operador de concatenação de strings + da Java Language Specification) fornece algumas informações mais detalhadas sobre por que o operador + pode ser tão lento.

0
Benedikt Waldvogel