¿Cuál es la principal diferencia entre StringBuffer
y StringBuilder
? ¿Hay algún problema de rendimiento al decidir sobre alguno de estos?
¿Cuál es la principal diferencia entre StringBuffer
y StringBuilder
? ¿Hay algún problema de rendimiento al decidir sobre alguno de estos?
Respuestas:
StringBuffer
está sincronizado, StringBuilder
no lo está.
StringBuilder
es más rápido que StringBuffer
porque no lo es synchronized
.
Aquí hay una prueba de referencia simple:
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);
}
}
}
Una prueba de funcionamiento da los números de 2241 ms
for StringBuffer
vs 753 ms
for StringBuilder
.
--> 0
en un bucle. Me tomó un momento darme cuenta de lo que significa. ¿Es esto algo que realmente se usa en la práctica en lugar de la ...; i > 0; i--
sintaxis habitual ?
i -->
es realmente molesto en cuanto a la sintaxis ... Al principio pensé que era una flecha debido a los comentarios sobre el arte ASCII.
main()
Además, su punto de referencia es injusto. No hay calentamiento.
Básicamente, los StringBuffer
métodos se sincronizan mientras que StringBuilder
no.
Las operaciones son "casi" iguales, pero usar métodos sincronizados en un solo hilo es excesivo.
Eso es más o menos al respecto.
Cita de la API StringBuilder :
Esta clase [StringBuilder] proporciona una API compatible con StringBuffer, pero sin garantía de sincronización . Esta clase está diseñada para usarse como un reemplazo directo para StringBuffer en lugares donde un único subproceso estaba utilizando el búfer de cadena (como suele ser el caso). Siempre que sea posible, se recomienda que esta clase se use con preferencia a StringBuffer, ya que será más rápida en la mayoría de las implementaciones.
Entonces se hizo para sustituirlo.
Lo mismo sucedió con Vector
y ArrayList
.
Hashtable
y HashMap
.
¿Pero necesitaba obtener la clara diferencia con la ayuda de un ejemplo?
StringBuffer o StringBuilder
Simplemente use a StringBuilder
menos que realmente esté tratando de compartir un búfer entre hilos. StringBuilder
es el hermano menor no sincronizado (menos sobrecarga = más eficiente) de la StringBuffer
clase sincronizada original .
StringBuffer
vino primero. Sun estaba preocupado por la corrección en todas las condiciones, por lo que lo sincronizaron para que sea seguro para subprocesos por si acaso.
StringBuilder
vino después La mayoría de los usos de StringBuffer
eran de un solo hilo y pagaban innecesariamente el costo de la sincronización.
Dado que StringBuilder
es un reemplazo directo StringBuffer
sin la sincronización, no habría diferencias entre los ejemplos.
Si está tratando de compartir entre hilos, puede usar StringBuffer
, pero considere si es necesaria una sincronización de nivel superior, por ejemplo, tal vez en lugar de usar StringBuffer, si sincroniza los métodos que usan StringBuilder.
Primero veamos las similitudes : StringBuilder y StringBuffer son mutables. Eso significa que puede cambiar el contenido de ellos, en la misma ubicación.
Diferencias : StringBuffer también es mutable y está sincronizado. Donde como StringBuilder es mutable pero no está sincronizado de forma predeterminada.
Significado de sincronizado (sincronización) : cuando algo está sincronizado, pueden acceder múltiples hilos y modificarlo sin ningún problema o efecto secundario. StringBuffer está sincronizado, por lo que puede usarlo con múltiples hilos sin ningún problema.
¿Cuál usar cuando? StringBuilder: cuando necesita una cadena, que puede ser modificable, y solo un hilo está accediendo y modificándola. StringBuffer: cuando necesita una cadena, que puede ser modificable, y múltiples hilos están accediendo y modificándola.
Nota : No use StringBuffer innecesariamente, es decir, no lo use si solo un subproceso está modificando y accediendo a él porque tiene mucho código de bloqueo y desbloqueo para la sincronización que innecesariamente tomará tiempo de CPU. No use cerraduras a menos que sea necesario.
En subprocesos individuales, StringBuffer no es significativamente más lento que StringBuilder , gracias a las optimizaciones de JVM. Y en subprocesos múltiples, no puede usar de forma segura un StringBuilder.
Aquí está mi prueba (no un punto de referencia, solo una prueba):
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:
cadenas: 319740
Buffers: 23
Generador: 7!
Por lo tanto, los constructores son más rápidos que los búferes, y MUCHO más rápido que la concatenación de cadenas. Ahora usemos un ejecutor para múltiples hilos:
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);
}
}
Ahora los StringBuffers tardan 157 ms para 100000 anexos. No es la misma prueba, pero en comparación con los 37 ms anteriores, puede asumir con seguridad que los anexos de StringBuffers son más lentos con el uso de subprocesos múltiples . La razón es que el JIT / punto de acceso / compilador / algo hace optimizaciones cuando detecta que no hay necesidad de verificar los bloqueos.
Pero con StringBuilder, tiene java.lang.ArrayIndexOutOfBoundsException , porque un hilo concurrente intenta agregar algo donde no debería.
La conclusión es que no tienes que perseguir a StringBuffers. Y donde tenga hilos, piense en lo que están haciendo, antes de intentar ganar unos pocos nanosegundos.
withString+="some string"+i+" ; ";
no es equivalente a los otros dos bucles y, por lo tanto, no es una comparación justa.
StringBuilder se introdujo en Java 1.5, por lo que no funcionará con JVM anteriores.
De los Javadocs :
La clase StringBuilder proporciona una API compatible con StringBuffer, pero sin garantía de sincronización. Esta clase está diseñada para usarse como un reemplazo directo para StringBuffer en lugares donde un único subproceso estaba utilizando el búfer de cadena (como suele ser el caso). Siempre que sea posible, se recomienda que esta clase se use con preferencia a StringBuffer, ya que será más rápida en la mayoría de las implementaciones.
StringBuilder
.
Bastante buena pregunta
Aquí están las diferencias, he notado:
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.
Cosa común :-
Ambos tienen los mismos métodos con las mismas firmas. Ambos son mutables.
StringBuffer
StringBuilder
StringBuffer
sin ningún otro cambioappend
dos veces, o append
y toString
no no es seguro.
StringBuilder no es seguro para subprocesos. String Buffer es. Más información aquí .
EDITAR: En cuanto al rendimiento, después de que se activa el punto de acceso , StringBuilder es el ganador. Sin embargo, para pequeñas iteraciones, la diferencia de rendimiento es insignificante.
StringBuilder
y StringBuffer
son casi lo mismo La diferencia es que StringBuffer
está sincronizado y StringBuilder
no lo está. Aunque, StringBuilder
es más rápido que StringBuffer
, la diferencia en el rendimiento es muy pequeña. StringBuilder
es un reemplazo de SUN de StringBuffer
. Simplemente evita la sincronización de todos los métodos públicos. En lugar de eso, su funcionalidad es la misma.
Ejemplo de buen uso:
Si su texto va a cambiar y es usado por múltiples hilos, entonces es mejor usarlo StringBuffer
. Si su texto va a cambiar pero es usado por un solo hilo, entonces úselo StringBuilder
.
StringBuffer
StringBuffer es mutable significa que uno puede cambiar el valor del objeto. El objeto creado a través de StringBuffer se almacena en el montón. StringBuffer tiene los mismos métodos que StringBuilder, pero cada método en StringBuffer está sincronizado, es decir, StringBuffer es seguro para subprocesos.
Debido a esto, no permite que dos hilos accedan simultáneamente al mismo método. Se puede acceder a cada método por un hilo a la vez.
Pero ser seguro para subprocesos también tiene desventajas ya que el rendimiento de StringBuffer impacta debido a la propiedad segura para subprocesos. Por lo tanto, StringBuilder es más rápido que StringBuffer cuando llama a los mismos métodos de cada clase.
El valor de StringBuffer se puede cambiar, significa que se puede asignar al nuevo valor. Hoy en día es una pregunta de entrevista más común, las diferencias entre las clases anteriores. String Buffer se puede convertir a la cadena mediante el 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 es igual que StringBuffer, es decir, almacena el objeto en el montón y también se puede modificar. La principal diferencia entre StringBuffer y StringBuilder es que StringBuilder tampoco es seguro para subprocesos. StringBuilder es rápido ya que no es seguro para subprocesos.
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
Es un inmutable.
StringBuffer
Es un mutable y sincronizado.
StringBuilder
también es mutable pero no está sincronizado.
El javadoc explica la diferencia:
Esta clase proporciona una API compatible con StringBuffer, pero sin garantía de sincronización. Esta clase está diseñada para usarse como un reemplazo directo para StringBuffer en lugares donde un único subproceso estaba utilizando el búfer de cadena (como suele ser el caso). Siempre que sea posible, se recomienda que esta clase se use con preferencia a StringBuffer, ya que será más rápida en la mayoría de las implementaciones.
StringBuilder
(introducido en Java 5) es idéntico a StringBuffer
, excepto que sus métodos no están sincronizados. Esto significa que tiene un mejor rendimiento que este último, pero el inconveniente es que no es seguro para subprocesos.
Lea el tutorial para más detalles.
Un programa simple que ilustra la diferencia entre StringBuffer y 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 se usa para almacenar cadenas de caracteres que se cambiarán (los objetos de cadena no se pueden cambiar). Se expande automáticamente según sea necesario. Clases relacionadas: String, CharSequence.
StringBuilder se agregó en Java 5. Es idéntico en todos los aspectos a StringBuffer, excepto que no está sincronizado, lo que significa que si varios subprocesos acceden al mismo tiempo, podría haber problemas. Para los programas de un solo subproceso, el caso más común, evitar la sobrecarga de sincronización hace que StringBuilder sea un poco más rápido.
StringBuilder
s generalmente son locales para un método, donde solo son visibles para un subproceso.
StringBuffer
está sincronizado, pero StringBuilder
no lo está. Como resultado, StringBuilder
es más rápido que StringBuffer
.
StringBuffer es mutable. Puede cambiar en términos de longitud y contenido. Los StringBuffers son seguros para subprocesos, lo que significa que tienen métodos sincronizados para controlar el acceso, de modo que solo un subproceso puede acceder al código sincronizado de un objeto StringBuffer a la vez. Por lo tanto, los objetos StringBuffer son generalmente seguros de usar en un entorno de subprocesos múltiples donde varios subprocesos pueden estar intentando acceder al mismo objeto StringBuffer al mismo tiempo.
StringBuilder La clase StringBuilder es muy similar a StringBuffer, excepto que su acceso no está sincronizado, por lo que no es seguro para subprocesos. Al no estar sincronizado, el rendimiento de StringBuilder puede ser mejor que StringBuffer. Por lo tanto, si está trabajando en un entorno de subproceso único, el uso de StringBuilder en lugar de StringBuffer puede aumentar el rendimiento. Esto también es cierto para otras situaciones, como una variable local StringBuilder (es decir, una variable dentro de un método) donde solo un hilo accederá a un objeto StringBuilder.
StringBuffer:
StringBuilder
String c = a + b
es equivalente a String c = new StringBuilder().append(a).append(b).toString()
, por lo que no es más rápido. Es sólo que crear uno nuevo para cada asignación de cadena, mientras que usted podría tener sólo uno ( String d = a + b; d = d + c;
es String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();
mientras StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();
se ahorraría una instanciation StringBuilder).
Constructor de cadenas :
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.
String-Buffer
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
Se recomienda usar StringBuilder siempre que sea posible porque es más rápido que StringBuffer. Sin embargo, si la seguridad del subproceso es necesaria, la mejor opción son los objetos StringBuffer.
Mejor uso StringBuilder
ya que no está sincronizado y, por lo tanto, ofrece un mejor rendimiento. StringBuilder
es un reemplazo directo de los más antiguos StringBuffer
.
StringBu(ff|ild)er
es una variable local utilizada solo por un solo hilo.
Dado que StringBuffer
está sincronizado, necesita un esfuerzo adicional, por lo tanto, basado en perforación, es un poco más lento que StringBuilder
.
No hay diferencias básicas entre StringBuilder
y StringBuffer
, solo existen unas pocas diferencias entre ellos. En StringBuffer
los métodos están sincronizados. Esto significa que a la vez solo un hilo puede operar en ellos. Si hay más de un hilo, el segundo tendrá que esperar a que termine el primero y el tercero tendrá que esperar a que terminen el primero y el segundo, y así sucesivamente. Esto hace que el proceso sea muy lento y, por lo tanto, el rendimiento en el caso StringBuffer
es bajo.
Por otro lado, StringBuilder
no está sincronizado. Esto significa que a la vez pueden operar múltiples hilos en el mismo StringBuilder
objeto al mismo tiempo. Esto hace que el proceso sea muy rápido y, por lo tanto, el rendimiento StringBuilder
es alto.
A String
es un objeto inmutable, lo que significa que el valor no se puede cambiar mientras que StringBuffer
es mutable.
El StringBuffer
está sincronizado, por lo tanto Hilo de seguridad mientras que StringBuilder
no y adecuado es, por únicos casos de un único subproceso.
La principal diferencia es que StringBuffer
está sincronizada, pero no lo StringBuilder
está. Si necesita usar más de un hilo, se recomienda StringBuffer. Pero , según la velocidad de ejecución, StringBuilder
es más rápida que StringBuffer
porque no está sincronizada.
Verifique las partes internas del método de adición sincronizada de StringBuffer
y el método de adición no sincronizada 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 agregar es synchronized
, StringBuffer
tiene una sobrecarga de rendimiento en comparación con el StrinbBuilder
escenario de subprocesos múltiples. Siempre y cuando no esté compartiendo el búfer entre varios subprocesos, use StringBuilder
, lo que es rápido debido a la ausencia de synchronized
métodos in append.
Aquí está el resultado de la prueba de rendimiento para String vs StringBuffer vs StringBuilder . Finalmente, StringBuilder ganó la prueba. Vea a continuación el código de prueba y el resultado.
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 iteraciones para agregar un solo texto
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 iteraciones para agregar un solo texto
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer está sincronizado y es seguro para subprocesos, StringBuilder no está sincronizado y es más rápido.