java - String, StringBuffer y StringBuilder
stringbuffer vs stringbuilder (11)
¿Por favor, dime una situación en tiempo real para comparar String
, StringBuffer
y StringBuilder
?
¿Quieres decir, por concatenación?
Ejemplo del mundo real: desea crear una nueva cadena a partir de muchas otras .
Por ejemplo para enviar un mensaje:
Cuerda
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I''m " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I''m " ).append( user.age ).append( "yrs. old too")
.toString()
O
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (la sintaxis es exactamente igual que con StringBuilder, los efectos difieren)
Acerca de
StringBuffer
vs StringBuilder
Lo primero está sincronizado y luego no lo está.
Por lo tanto, si lo invoca varias veces en un solo subproceso (que es el 90% de los casos), StringBuilder
se ejecutará mucho más rápido porque no se detendrá para ver si posee el bloqueo del subproceso.
Por lo tanto, es recomendable usar StringBuilder
(a menos que, por supuesto, tenga más de un hilo accediendo a él al mismo tiempo, lo cual es raro)
String
compilador puede optimizar la concatenación de String
( con el operador + ) para usar StringBuilder
debajo, por lo que ya no es algo de qué preocuparse, en los días pasados de Java, esto era algo que todo el mundo dice que debería evitarse a toda costa, porque cada concatenación creó un nuevo objeto String. Los compiladores modernos ya no hacen esto, pero aún así es una buena práctica usar StringBuilder
lugar de usar un compilador "antiguo".
editar
Solo para quien es curioso, esto es lo que hace el compilador para esta clase:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
Las líneas numeradas del 5 al 27 son para la cadena llamada "literal"
Las líneas numeradas del 31 al 53 son para la cadena llamada "constructor"
No hay diferencia, se ejecuta exactamente el mismo código para ambas cadenas.
Además, StringBuffer
es seguro para subprocesos, lo que no es StringBuilder
.
Entonces, en una situación en tiempo real cuando diferentes hilos están accediendo a él, StringBuilder
podría tener un resultado indeterminista.
En java, String es inmutable. Al ser inmutables, queremos decir que una vez que se crea una Cadena, no podemos cambiar su valor. StringBuffer es mutable. Una vez que se crea un objeto StringBuffer, simplemente agregamos el contenido al valor del objeto en lugar de crear un nuevo objeto. StringBuilder es similar a StringBuffer pero no es seguro para subprocesos. Los métodos de StingBuilder no están sincronizados, pero en comparación con otras cadenas, el Stringbuilder se ejecuta más rápido. Puede aprender la diferencia entre String, StringBuilder y StringBuffer implementándolos.
La diferencia entre String y las otras dos clases es que String es inmutable y las otras dos son clases mutables.
¿Pero por qué tenemos dos clases para el mismo propósito?
La razón es que StringBuffer
es Thread safe y StringBuilder
no. StringBuilder
es una nueva clase en StringBuffer Api
y se introdujo en JDK5
y siempre se recomienda si está trabajando en un entorno de un solo hilo, ya que es mucho Faster
Para obtener detalles completos, puede leer http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
Personalmente, no creo que haya ningún uso del mundo real para StringBuffer
. ¿Cuándo querría comunicarme entre varios hilos manipulando una secuencia de caracteres? Eso no suena útil en absoluto, pero quizás aún no haya visto la luz :)
Tenga en cuenta que si está utilizando Java 5 o más reciente, debe usar StringBuilder
lugar de StringBuffer
. De la documentación de la API:
A partir de la versión JDK 5, esta clase se ha complementado con una clase equivalente diseñada para ser utilizada por un solo hilo,
StringBuilder
. La claseStringBuilder
generalmente se debe usar con preferencia a esta, ya que admite todas las mismas operaciones, pero es más rápida, ya que no realiza ninguna sincronización.
En la práctica, casi nunca usará esto desde varios subprocesos al mismo tiempo, por lo que la sincronización que hace StringBuffer
es casi siempre una sobrecarga innecesaria.
Cuerda
La String class
representa cadenas de caracteres. Todos los literales de cadena en el programa Java, como "abc"
se implementan como instancias de esta clase.
Los objetos de cadena son inmutables una vez que se crean, no podemos cambiarlos. (Las cuerdas son constantes )
Si se crea una cadena utilizando un constructor o un método, esas cadenas se almacenarán en la memoria del montón y en
SringConstantPool
. Pero antes de guardar en el grupo, invoca el métodointern()
para verificar la disponibilidad del objeto con el mismo contenido en el grupo utilizando el método equals. Si String-copy está disponible en el Pool, devuelve la referencia. De lo contrario, el objeto String se agrega a la agrupación y devuelve la referencia.- El lenguaje Java proporciona soporte especial para el operador de concatenación de cadenas (
+
) y para la conversión de otros objetos en cadenas. La concatenación de cadenas se implementa a través de la clase StringBuilder (o StringBuffer) y su método de adición.
String heapSCP = new String("Yash"); heapSCP.concat("."); heapSCP = heapSCP + "M"; heapSCP = heapSCP + 777; // For Example: String Source Code public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); }
- El lenguaje Java proporciona soporte especial para el operador de concatenación de cadenas (
Los literales de cadena se almacenan en
StringConstantPool
.String onlyPool = "Yash";
StringBuilder y StringBuffer son secuencias mutables de caracteres. Eso significa que uno puede cambiar el valor de estos objetos. StringBuffer tiene los mismos métodos que StringBuilder, pero cada método en StringBuffer está sincronizado, por lo que es seguro para subprocesos.
Los datos de StringBuffer y StringBuilder solo se pueden crear usando un nuevo operador. Por lo tanto, se almacenan en la memoria del montón.
Las instancias de StringBuilder no son seguras para ser utilizadas por múltiples hilos. Si se requiere tal sincronización, se recomienda que se utilice StringBuffer.
StringBuffer threadSafe = new StringBuffer("Yash"); threadSafe.append(".M"); threadSafe.toString(); StringBuilder nonSync = new StringBuilder("Yash"); nonSync.append(".M"); nonSync.toString();
StringBuffer y StringBuilder tienen métodos especiales como.,
replace(int start, int end, String str)
yreverse()
.NOTA : StringBuffer y SringBuilder son mutables, ya que proporcionan la implementación de la
Appendable Interface
.
Cuándo usar cuál.
Si no va a cambiar el valor cada vez, entonces es mejor usar
String Class
. Como parte de Generics, si desea ordenarComparable<T>
o comparar valores, vaya aString Class
.//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable Set<StringBuffer> set = new TreeSet<StringBuffer>(); set.add( threadSafe ); System.out.println("Set : "+ set);
Si va a modificar el valor cada vez que vaya a StringBuilder, que es más rápido que StringBuffer. Si múltiples hilos están modificando el valor, vaya para StringBuffer.
Diferencia de mutabilidad:
String
es inmutable , si intenta modificar sus valores, se crea otro objeto, mientras que StringBuffer
y StringBuilder
son mutables para que puedan cambiar sus valores.
Diferencia de seguridad del hilo:
La diferencia entre StringBuffer
y StringBuilder
es que StringBuffer
es seguro para subprocesos. Por lo tanto, cuando la aplicación solo se debe ejecutar en un único subproceso, es mejor usar StringBuilder
. StringBuilder
es más eficiente que StringBuffer
.
Situaciones:
- Si su cadena no va a cambiar, use una clase de cadena porque un objeto de
String
es inmutable. - Si su cadena puede cambiar (ejemplo: mucha lógica y operaciones en la construcción de la cadena) y solo se accederá desde un solo hilo, usar un
StringBuilder
es suficiente. - Si su cadena puede cambiar y se podrá acceder a ella desde varios subprocesos, use un
StringBuffer
porqueStringBuffer
es síncrono, por lo que tiene seguridad para subprocesos.
Los basicos:
String
es una clase inmutable, no se puede cambiar. StringBuilder
es una clase mutable a la que se pueden agregar, que los caracteres se pueden reemplazar o eliminar y, en última instancia, se convierten en StringBuffer
es la versión sincronizada original de StringBuilder
Debería preferir StringBuilder
en todos los casos en los que tenga un solo hilo que acceda a su objeto.
Los detalles:
También tenga en cuenta que StringBuilder/Buffers
no son mágicos, solo usan un Array como un objeto de respaldo y que el Array tiene que ser reasignado cuando se llena. Asegúrese de crear sus objetos StringBuilder/Buffer
suficientemente grandes originalmente para que no tengan que cambiar su tamaño constantemente cada vez que se llama a .append()
.
El cambio de tamaño puede llegar a ser muy degenerado. Básicamente, cambia el tamaño de la matriz de respaldo a 2 veces su tamaño actual cada vez que se debe ampliar. Esto puede hacer que se asignen grandes cantidades de RAM y no se utilicen cuando las clases de StringBuilder/Buffer
comiencen a crecer.
En Java String x = "A" + "B";
utiliza un StringBuilder
detrás de las escenas. Entonces, para casos simples, no hay beneficio de declarar los tuyos. Pero si está creando objetos String
que son grandes, digamos menos de 4k y luego declare StringBuilder sb = StringBuilder(4096);
es mucho más eficiente que la concatenación o el uso del constructor predeterminado, que tiene solo 16 caracteres. Si su String
va a ser inferior a 10k, inicialícelo con el constructor a 10k para estar seguro. Pero si se inicializa a 10k, entonces escribe 1 carácter más de 10k, se volverá a asignar y se copiará a una matriz de 20k. Así que inicializar alto es mejor que a bajo.
En el caso de cambio de tamaño automático, en el 17º carácter, la matriz de respaldo se vuelve a asignar y se copia a 32 caracteres; en el 33º carácter, esto vuelve a suceder y se vuelve a asignar y copia la matriz en 64 caracteres. Puede ver cómo esto degenera en muchas reasignaciones y copias, que es lo que realmente está tratando de evitar usando StringBuilder/Buffer
en primer lugar.
Esto es del código fuente de JDK 6 para AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
Una buena práctica es inicializar el StringBuilder/Buffer
un poco más grande de lo que crees que necesitarás si no sabes de inmediato qué tan grande será el String
pero puedes adivinarlo. Una asignación de un poco más de memoria de la que necesita será mejor que muchas reasignaciones y copias.
También tenga cuidado de inicializar un StringBuilder/Buffer
con un String
ya que solo asignará el tamaño del String + 16 caracteres, que en la mayoría de los casos solo iniciará la reasignación degenerada y el ciclo de copia que está tratando de evitar. Lo siguiente es directamente del código fuente de Java 6.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Si por casualidad terminas con una instancia de StringBuilder/Buffer
que no creaste y no puedes controlar el constructor al que se llama, hay una manera de evitar el degenerado comportamiento de reasignación y copia. Llame a .ensureCapacity()
con el tamaño que desea para garantizar que su String
resultante se ajuste.
Las alternativas:
Solo como una nota, si estás haciendo una construcción y manipulación de String
realmente pesada , hay una alternativa mucho más orientada al rendimiento llamada Ropes .
Otra alternativa es crear una implementación de StringList
mediante una StringList
de ArrayList<String>
, y agregando contadores para rastrear el número de caracteres en cada .append()
y otras operaciones de mutación de la lista, luego .toString()
para crear un StringBuilder
del tamaño exacto que necesita y recorre la lista y genera la salida, incluso puede hacer que StringBuilder
una variable de instancia y "almacenar en caché" los resultados de .toString()
y solo tiene que volver a generarla cuando algo cambie.
Además, no se olvide de String.format()
al crear una salida con formato fijo, que el compilador puede optimizar a medida que lo hacen mejor.
---------------------------------------------------------------------------------- String StringBuffer StringBuilder ---------------------------------------------------------------------------------- Storage Area | Constant String Pool Heap Heap Modifiable | No (immutable) Yes( mutable ) Yes( mutable ) Thread Safe | Yes Yes No Performance | Fast Very slow Fast ----------------------------------------------------------------------------------
- Usas
String
cuando una estructura inmutable es apropiada; la obtención de una nueva secuencia de caracteres de unaString
puede conllevar una penalización de rendimiento inaceptable, ya sea en el tiempo de CPU o en la memoria (la obtención de subcadenas es eficiente en la CPU porque los datos no se copian, pero esto significa que es posible que se asigne una cantidad de datos mucho mayor). - Utiliza
StringBuilder
cuando necesitas crear una secuencia de caracteres mutable, generalmente para concatenar varias secuencias de caracteres juntas. - Usted usa
StringBuffer
en las mismas circunstancias que usaríaStringBuilder
, pero cuando los cambios en la cadena subyacente deben estar sincronizados (debido a que varias cadenas están leyendo / modificando el búfer de la cadena).
Vea un ejemplo here .