Qual é a principal diferença entre StringBuffere StringBuilder? Há algum problema de desempenho ao decidir sobre qualquer um deles?
Qual é a principal diferença entre StringBuffere StringBuilder? Há algum problema de desempenho ao decidir sobre qualquer um deles?
Respostas:
StringBufferestá sincronizado, StringBuildernão está.
StringBuilderé mais rápido do que StringBufferporque não é synchronized.
Aqui está um teste de benchmark simples:
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
Uma execução de teste fornece os números de 2241 msfor StringBuffervs 753 msfor StringBuilder.
--> 0um loop. Levei um momento para perceber o que isso significa. Isso é algo que é realmente usado na prática, em vez da ...; i > 0; i--sintaxe usual ?
i -->é realmente irritante em termos de sintaxe ... Eu pensei que era uma flecha a princípio por causa dos comentários sobre a arte ASCII.
main()Além disso, seu benchmark é injusto. Não há aquecimento.
Basicamente, os StringBuffermétodos são sincronizados enquanto StringBuildernão são.
As operações são "quase" iguais, mas o uso de métodos sincronizados em um único encadeamento é um exagero.
É praticamente isso.
Citação da API StringBuilder :
Esta classe [StringBuilder] fornece uma API compatível com StringBuffer, mas sem garantia de sincronização . Essa classe foi projetada para ser usada como um substituto para o StringBuffer nos locais em que o buffer da string estava sendo usado por um único encadeamento (como geralmente é o caso). Onde possível, é recomendável que essa classe seja usada preferencialmente ao StringBuffer, pois será mais rápida na maioria das implementações.
Então foi feito para substituí-lo.
O mesmo aconteceu com Vectore ArrayList.
Hashtablee HashMap.
Mas precisava obter a diferença clara com a ajuda de um exemplo?
StringBuffer ou StringBuilder
Basta usar, a StringBuildermenos que você esteja realmente tentando compartilhar um buffer entre os threads. StringBuilderé o irmão mais novo não sincronizado (menos sobrecarga = mais eficiente) da StringBufferclasse sincronizada original .
StringBufferveio primeiro. A Sun estava preocupada com a correção em todas as condições, por isso a sincronizaram para garantir a segurança de threads.
StringBuilderveio mais tarde. A maioria dos usos StringBufferera de thread único e pagava desnecessariamente o custo da sincronização.
Como StringBuilderé um substituto substituto para StringBuffersem a sincronização, não haveria diferenças entre nenhum exemplo.
Se você está tentando compartilhar entre threads, pode usar StringBuffer, mas considere se a sincronização de nível superior é necessária, por exemplo, talvez em vez de usar StringBuffer, você deve sincronizar os métodos que usam o StringBuilder.
Primeiro vamos ver as semelhanças : StringBuilder e StringBuffer são mutáveis. Isso significa que você pode alterar o conteúdo deles, no mesmo local.
Diferenças : StringBuffer é mutável e sincronizado também. Onde, como StringBuilder, é mutável, mas não sincronizado por padrão.
Significado de sincronizado (sincronização) : quando algo é sincronizado, vários threads podem acessar e modificá-lo sem nenhum problema ou efeito colateral. StringBuffer é sincronizado, para que você possa usá-lo com vários threads sem qualquer problema.
Qual usar quando? StringBuilder: quando você precisa de uma string, que pode ser modificável, e apenas um thread a está acessando e modificando. StringBuffer: quando você precisa de uma string, que pode ser modificável, e vários threads a acessam e modificam.
Nota : Não use StringBuffer desnecessariamente, ou seja, não use-o se apenas um segmento estiver modificando e acessando-o, pois possui muito código de bloqueio e desbloqueio para sincronização, o que consumirá desnecessariamente o tempo da CPU. Não use bloqueios, a menos que seja necessário.
Em threads únicos, o StringBuffer não é significativamente mais lento que o StringBuilder , graças às otimizações da JVM. E no multithreading, você não pode usar com segurança um StringBuilder.
Aqui está o meu teste (não uma referência, apenas um teste):
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
Resultados:
strings: 319740
Buffers: 23
Construtor: 7!
Portanto, os construtores são mais rápidos que os buffers e muito mais rápidos que a concatenação de strings. Agora vamos usar um Executor para vários threads:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
Agora, os StringBuffers levam 157 ms para 100000 anexos. Não é o mesmo teste, mas comparado aos 37 ms anteriores, você pode assumir com segurança que os anexos de StringBuffers são mais lentos com o uso de multithreading . O motivo é que o JIT / hotspot / compiler / something faz otimizações quando detecta que não há necessidade de verificar bloqueios.
Mas com StringBuilder, você tem java.lang.ArrayIndexOutOfBoundsException , porque um encadeamento simultâneo tenta adicionar algo que não deveria.
A conclusão é que você não precisa perseguir StringBuffers. E onde você tem tópicos, pense no que eles estão fazendo, antes de tentar ganhar alguns nanossegundos.
withString+="some string"+i+" ; ";não é equivalente aos outros dois loops e, portanto, não é uma comparação justa.
O StringBuilder foi introduzido no Java 1.5 para não funcionar com JVMs anteriores.
Dos Javadocs :
A classe StringBuilder fornece uma API compatível com StringBuffer, mas sem garantia de sincronização. Essa classe foi projetada para ser usada como um substituto para o StringBuffer nos locais em que o buffer da string estava sendo usado por um único encadeamento (como geralmente é o caso). Onde possível, é recomendável que essa classe seja usada preferencialmente ao StringBuffer, pois será mais rápida na maioria das implementações.
StringBuilder.
Pretty Good Question
Aqui estão as diferenças, notei:
StringBuffer: -
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder: -
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
Coisa comum :-
Ambos têm os mesmos métodos com as mesmas assinaturas. Ambos são mutáveis.
StringBuffer
StringBuilder
StringBuffersem nenhuma outra alteraçãoappendduas vezes, ou appende toStringnão, não é seguro.
StringBuildere StringBuffersão quase os mesmos. A diferença é que StringBufferestá sincronizado e StringBuildernão está. Embora, StringBuilderseja mais rápido que StringBuffer, a diferença de desempenho é muito pequena. StringBuilderé um substituto de SUN StringBuffer. Apenas evita a sincronização de todos os métodos públicos. Em vez disso, sua funcionalidade é a mesma.
Exemplo de bom uso:
Se o seu texto for alterado e for usado por vários threads, é melhor usá-lo StringBuffer. Se o seu texto for alterado, mas for usado por um único thread, use StringBuilder.
StringBuffer
StringBuffer é mutável significa que é possível alterar o valor do objeto. O objeto criado por meio de StringBuffer é armazenado no heap. StringBuffer possui os mesmos métodos que o StringBuilder, mas cada método no StringBuffer é sincronizado, ou seja, StringBuffer é seguro para threads.
por isso, não permite que dois threads acessem simultaneamente o mesmo método. Cada método pode ser acessado por um thread por vez.
Mas ser seguro para threads também tem desvantagens, pois o desempenho do StringBuffer atinge devido à propriedade segura para threads. Portanto, StringBuilder é mais rápido que o StringBuffer ao chamar os mesmos métodos de cada classe.
O valor StringBuffer pode ser alterado, significa que pode ser atribuído ao novo valor. Hoje em dia é uma pergunta de entrevista mais comum, as diferenças entre as classes acima. O buffer de string pode ser convertido em string usando o método toString ().
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder é igual ao StringBuffer, ou seja, armazena o objeto na pilha e também pode ser modificado. A principal diferença entre o StringBuffer e o StringBuilder é que o StringBuilder também não é seguro para threads. O StringBuilder é rápido, pois não é seguro para threads.
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
String é um imutável.
StringBuffer é um mutável e sincronizado.
StringBuilder também é mutável, mas não está sincronizado.
O javadoc explica a diferença:
Esta classe fornece uma API compatível com StringBuffer, mas sem garantia de sincronização. Essa classe foi projetada para ser usada como um substituto para o StringBuffer nos locais em que o buffer da string estava sendo usado por um único encadeamento (como geralmente é o caso). Onde possível, é recomendável que essa classe seja usada preferencialmente ao StringBuffer, pois será mais rápida na maioria das implementações.
StringBuilder(introduzido no Java 5) é idêntico a StringBuffer, exceto que seus métodos não são sincronizados. Isso significa que ele tem um desempenho melhor que o último, mas a desvantagem é que não é seguro para threads.
Leia o tutorial para mais detalhes.
Um programa simples que ilustra a diferença entre StringBuffer e StringBuilder:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer é usado para armazenar seqüências de caracteres que serão alteradas (os objetos String não podem ser alterados). Expande automaticamente conforme necessário. Classes relacionadas: String, CharSequence.
O StringBuilder foi adicionado no Java 5. É idêntico em todos os aspectos ao StringBuffer, exceto pelo fato de não estar sincronizado, o que significa que se vários encadeamentos estiverem acessando-o ao mesmo tempo, poderá haver problemas. Para programas de thread único, o caso mais comum, evitando a sobrecarga da sincronização, torna o StringBuilder muito mais rápido.
StringBuildergeralmente são locais para um método, onde são visíveis para apenas um thread.
StringBufferestá sincronizado, mas StringBuildernão está. Como resultado, StringBuilderé mais rápido que StringBuffer.
StringBuffer é mutável. Pode mudar em termos de tamanho e conteúdo. StringBuffers são seguros para threads, o que significa que eles têm métodos sincronizados para controlar o acesso, para que apenas um thread possa acessar o código sincronizado de um objeto StringBuffer por vez. Portanto, os objetos StringBuffer geralmente são seguros para uso em um ambiente com vários threads em que vários threads podem estar tentando acessar o mesmo objeto StringBuffer ao mesmo tempo.
StringBuilder A classe StringBuilder é muito semelhante ao StringBuffer, exceto que seu acesso não é sincronizado para que não seja seguro para threads. Por não ser sincronizado, o desempenho do StringBuilder pode ser melhor que o StringBuffer. Portanto, se você estiver trabalhando em um ambiente de thread único, o uso de StringBuilder em vez de StringBuffer pode resultar em aumento de desempenho. Isso também se aplica a outras situações, como uma variável local StringBuilder (ou seja, uma variável dentro de um método) em que apenas um thread acessará um objeto StringBuilder.
StringBuffer:
StringBuilder
String c = a + bé equivalente a String c = new StringBuilder().append(a).append(b).toString(), portanto, não é mais rápido. É só que você criar um novo para cada atribuição corda, enquanto você poderia ter apenas um ( String d = a + b; d = d + c;é String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();ao mesmo tempo StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();iria salvar uma instanciação StringBuilder).
Construtor de String :
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
Buffer de String
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
É recomendável usar o StringBuilder sempre que possível, porque é mais rápido que o StringBuffer. No entanto, se a segurança do encadeamento for necessária, a melhor opção são os objetos StringBuffer.
Melhor uso, StringBuilderpois não é sincronizado e, portanto, oferece melhor desempenho. StringBuilderé um substituto direto do antigo StringBuffer.
StringBu(ff|ild)eré uma variável local usada apenas por um único thread.
Como StringBufferé sincronizado, ele precisa de algum esforço extra, portanto, com base no desempenho, é um pouco mais lento que StringBuilder.
Não há diferenças básicas entre StringBuildere StringBuffer, existem apenas algumas diferenças entre eles. Nos StringBuffermétodos são sincronizados. Isso significa que por vez, apenas um segmento pode operar com eles. Se houver mais de um encadeamento, o segundo encadeamento terá que aguardar o término do primeiro e o terceiro precisará aguardar o término do primeiro e do segundo e assim por diante. Isso torna o processo muito lento e, portanto, o desempenho no caso de StringBufferé baixo.
Por outro lado, StringBuildernão está sincronizado. Isso significa que ao mesmo tempo vários threads podem operar no mesmo StringBuilderobjeto ao mesmo tempo. Isso torna o processo muito rápido e, portanto, o desempenho StringBuilderé alto.
A Stringé um objeto imutável, o que significa que o valor não pode ser alterado enquanto StringBufferé mutável.
O StringBufferé sincronizado, portanto, é seguro para threads, enquanto StringBuildernão é adequado para apenas instâncias de thread único.
A principal diferença é StringBufferestá sincronizado mas StringBuilderé not.If você precisa usar mais de um segmento, então StringBuffer é recommended.But, de acordo com a velocidade de execução StringBuilderé mais rápido que StringBuffer, porque não é sincronizado.
Verifique as características internas do método de acréscimo sincronizado StringBuffere do método de acréscimo não sincronizado de StringBuilder.
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
Como o anexo é synchronized, StringBufferpossui uma sobrecarga de desempenho em comparação com o StrinbBuildercenário de multiencadeamento. Contanto que você não esteja compartilhando buffer entre vários encadeamentos, use StringBuilder, o que é rápido devido à ausência de synchronizedmétodos append.
Aqui está o resultado do teste de desempenho para String vs StringBuffer vs StringBuilder . Finalmente, o StringBuilder venceu o teste. Veja abaixo o código e o resultado do teste.
Código :
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
Resultado :
100000 iteração para adicionar um único texto
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 iteração para adicionar um único texto
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer é sincronizado e seguro para threads, StringBuilder não é sincronizado e mais rápido.