Qual é a principal diferença entre StringBuffer
e StringBuilder
? Há algum problema de desempenho ao decidir sobre qualquer um deles?
Qual é a principal diferença entre StringBuffer
e StringBuilder
? Há algum problema de desempenho ao decidir sobre qualquer um deles?
Respostas:
StringBuffer
está sincronizado, StringBuilder
não está.
StringBuilder
é mais rápido do que StringBuffer
porque 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 ms
for StringBuffer
vs 753 ms
for StringBuilder
.
--> 0
um 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 StringBuffer
métodos são sincronizados enquanto StringBuilder
nã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 Vector
e ArrayList
.
Hashtable
e HashMap
.
Mas precisava obter a diferença clara com a ajuda de um exemplo?
StringBuffer ou StringBuilder
Basta usar, a StringBuilder
menos 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 StringBuffer
classe sincronizada original .
StringBuffer
veio 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.
StringBuilder
veio mais tarde. A maioria dos usos StringBuffer
era de thread único e pagava desnecessariamente o custo da sincronização.
Como StringBuilder
é um substituto substituto para StringBuffer
sem 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
StringBuffer
sem nenhuma outra alteraçãoappend
duas vezes, ou append
e toString
não, não é seguro.
StringBuilder
e StringBuffer
são quase os mesmos. A diferença é que StringBuffer
está sincronizado e StringBuilder
não está. Embora, StringBuilder
seja 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.
StringBuilder
geralmente são locais para um método, onde são visíveis para apenas um thread.
StringBuffer
está sincronizado, mas StringBuilder
nã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, StringBuilder
pois 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 StringBuilder
e StringBuffer
, existem apenas algumas diferenças entre eles. Nos StringBuffer
mé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, StringBuilder
não está sincronizado. Isso significa que ao mesmo tempo vários threads podem operar no mesmo StringBuilder
objeto 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 StringBuilder
não é adequado para apenas instâncias de thread único.
A principal diferença é StringBuffer
está 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 StringBuffer
e 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
, StringBuffer
possui uma sobrecarga de desempenho em comparação com o StrinbBuilder
cená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 synchronized
mé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.