Respuestas:
Diferencia de mutabilidad:
String
es inmutable , si intenta alterar sus valores, otro objeto se crea, 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 segura para subprocesos. Entonces, cuando la aplicación necesita ejecutarse solo en un solo hilo, entonces es mejor usarla StringBuilder
. StringBuilder
es más eficiente que StringBuffer
.
Situaciones
String
objeto es inmutable.StringBuilder
es lo suficientemente bueno.StringBuffer
porque StringBuffer
es sincrónico para que tenga seguridad de subprocesos.Strings
cuando modificamos el valor, se crea otro objeto. ¿La referencia de objeto anterior se anula para que pueda ser recolectada por la basura GC
o incluso se recolecta basura?
String
with StringBuilder
?
String
cuando una estructura inmutable es apropiada; obtener una nueva secuencia de caracteres de a String
puede llevar a una penalización de rendimiento inaceptable, ya sea en tiempo de CPU o memoria (obtener subcadenas es eficiente de CPU porque los datos no se copian, pero esto significa que una cantidad de datos potencialmente mucho mayor puede permanecer asignada).StringBuilder
cuando necesita crear una secuencia de caracteres mutable, generalmente para concatenar varias secuencias de caracteres juntas.StringBuffer
en las mismas circunstancias que se usaría StringBuilder
, pero cuando los cambios en la cadena subyacente se deben sincronizar (porque varios subprocesos están leyendo / modificando el búfer de cadena).Vea un ejemplo aquí .
Los basicos:
String
es una clase inmutable, no se puede cambiar.
StringBuilder
es una clase mutable a la que se puede agregar, reemplazar o eliminar caracteres y, en última instancia, convertir a String
StringBuffer
es la versión original sincronizada deStringBuilder
Debería preferir StringBuilder
en todos los casos en los que solo tiene un único hilo accediendo a su objeto.
Los detalles:
También tenga en cuenta que StringBuilder/Buffers
no son mágicos, solo usan una matriz como objeto de respaldo y que la matriz debe reasignarse cada vez que se llena. Asegúrate de crear tus StringBuilder/Buffer
objetos lo suficientemente grandes originalmente donde no tengan que volver a dimensionarse constantemente cada vez que .append()
se los llama.
El cambio de tamaño puede ser muy degenerado. Básicamente cambia el tamaño de la matriz de respaldo a 2 veces su tamaño actual cada vez que necesita expandirse. Esto puede provocar que se asignen grandes cantidades de RAM y que no se usen cuando las StringBuilder/Buffer
clases comienzan a crecer.
En Java String x = "A" + "B";
utiliza un StringBuilder
detrás de escena. Entonces, para casos simples, no hay beneficio de declarar el suyo propio. Pero si está construyendo String
objetos que son grandes, digamos menos de 4k, entonces declarar StringBuilder sb = StringBuilder(4096);
es mucho más eficiente que la concatenación o usar el constructor predeterminado que tiene solo 16 caracteres. Si String
va a tener menos de 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 reasignará y copiará en una matriz de 20k. Por lo tanto, inicializar alto es mejor que bajo.
En el caso de cambio de tamaño automático, en el 17º carácter, la matriz de respaldo se reasigna y se copia a 32 caracteres, en el 33º carácter esto vuelve a ocurrir y se puede reasignar y copiar 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 usar 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 mejor práctica es inicializar StringBuilder/Buffer
un poco más de lo que crees que vas a necesitar si no sabes de inmediato qué tan grande String
será, pero puedes adivinar. 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 a StringBuilder/Buffer
con a, String
ya que solo asignará el tamaño de los caracteres de Cadena + 16, que en la mayoría de los casos solo comenzará el ciclo de reasignación y copia degenerado 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
eso que no creaste y no puedes controlar el constructor que se llama, hay una manera de evitar el comportamiento degenerado de reasignación y copia. Llame .ensureCapacity()
con el tamaño que desea para asegurarse de que su resultado String
se ajuste.
Las alternativas
Solo como una nota, si está haciendo una String
construcción y manipulación realmente pesadas , hay una alternativa mucho más orientada al rendimiento llamada Ropes .
Otra alternativa es crear una StringList
implementación subclasificando ArrayList<String>
y agregando contadores para rastrear el número de caracteres en todas .append()
y cada una de las operaciones de mutación de la lista, luego anular .toString()
para crear uno StringBuilder
del tamaño exacto que necesita y recorrer la lista y construir en la salida, incluso puede convertir esa StringBuilder
variable en una instancia y 'almacenar en caché' los resultados .toString()
y solo tiene que volver a generarla cuando algo cambia.
Tampoco se olvide de String.format()
crear un formato de salida fijo, que el compilador puede optimizar a medida que lo mejoran.
String x = "A" + "B";
Realmente se compila para ser un StringBuilder? ¿Por qué no solo compilaría? String x = "AB";
Solo debería usar un StringBuilder si los componentes no se conocen en el momento de la compilación.
¿Te refieres a concatenación?
Ejemplo del mundo real: desea crear una nueva cadena a partir de muchos otros .
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 como con StringBuilder, los efectos difieren)
Acerca de
StringBuffer
vs. StringBuilder
El primero está sincronizado y luego no.
Entonces, si lo invoca varias veces en un solo hilo (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 hilo.
Por lo tanto, es recomendable usarlo StringBuilder
(a menos que, por supuesto, tenga más de un hilo accediendo al mismo tiempo, lo cual es raro)
String
el compilador puede optimizar la concatenación ( usando el operador + ) para usar StringBuilder
debajo, por lo que ya no es algo de qué preocuparse, en los días antiguos de Java, esto era algo que todo el mundo dice que debe 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 usarlo StringBuilder
en caso de que use un compilador "antiguo".
editar
Solo para quién tiene curiosidad, 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 denominada "constructor"
No hay diferencia, exactamente el mismo código se ejecuta para ambas cadenas.
StringBuilder
concatenación de cadenas para hacer en el lado derecho de la tarea. Cualquier buena implementación utilizará un StringBuilder detrás de escena como usted dice. Además, su ejemplo de "a" + "b"
se compilaría en un solo literal, "ab"
pero si lo usara, StringBuilder
se generarían dos llamadas innecesarias a append()
.
"a"+"b"
pero para decir qué era una concatenación de String, lo cambio para que sea explícito. Lo que no dice es por qué no es una buena práctica hacerlo. Eso es exactamente lo que hace un compilador (moderno). @fuzzy, estoy de acuerdo, especialmente cuando sabes cuál sería el tamaño de la cadena final (aprox.).
-------------------------------------------------- -------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- Área de almacenamiento | Montón de agrupación de cadenas constantes Modificable | No (inmutable) Sí (mutable) Sí (mutable) Hilo seguro | Si si no Rendimiento | Rápido Muy lento Rápido -------------------------------------------------- --------------------------------
synchronised
y esa es la razón .
Cuerda
El 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 cadenas son constantes )
Si se crea una cadena utilizando el constructor o el método a continuación, se almacenarán las cadenas en memoria de pila , así como SringConstantPool
. Pero antes de guardar en el grupo, invoca el intern()
método para verificar la disponibilidad de objetos con el mismo contenido en el grupo usando el método igual. Si String-copy está disponible en el Pool, entonces devuelve la referencia. De lo contrario, el objeto String se agrega al grupo y devuelve la referencia.
+
) y para la conversión de otros objetos a cadenas. La concatenación de cadenas se implementa a través de la clase StringBuilder (o StringBuffer) y su método append.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);
}
Los literales de cadena se almacenan en StringConstantPool
.
String onlyPool = "Yash";
StringBuilder y StringBuffer son secuencias de caracteres mutables. 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 con un nuevo operador. Por lo tanto, se almacenan en la memoria del montón.
Las instancias de StringBuilder no son seguras para su uso por varios subprocesos. Si se requiere dicha sincronización, se recomienda utilizar StringBuffer.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer y StringBuilder están teniendo un métodos especiales como.,
replace(int start, int end, String str)
Y reverse()
.
NOTA : StringBuffer y SringBuilder son mutables ya que proporcionan la implementación de
Appendable Interface
.
Cuándo usar cuál.
Si no va a cambiar el valor cada vez, es mejor usarlo String Class
. Como parte de Generics, si desea ordenar Comparable<T>
o comparar valores, elija String 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 varios hilos están modificando el valor, vaya a StringBuffer.
Además, StringBuffer
es seguro para subprocesos, que StringBuilder
no lo es.
Por lo tanto, en una situación en tiempo real cuando diferentes subprocesos acceden a él, StringBuilder
podría tener un resultado indeterminado.
Tenga en cuenta que si está utilizando Java 5 o más reciente, debe usarlo en StringBuilder
lugar de StringBuffer
. De la documentación de la API:
Como de la liberación de JDK 5, esta clase se ha complementado con una clase equivalente diseñado para su uso por un solo hilo,
StringBuilder
. LaStringBuilder
clase 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 sincronización.
En la práctica, casi nunca usará esto de varios subprocesos al mismo tiempo, por lo que la sincronización StringBuffer
es casi siempre innecesaria.
Personalmente, no creo que haya un uso real en el mundo StringBuffer
. ¿Cuándo querría comunicarme entre múltiples hilos manipulando una secuencia de caracteres? Eso no suena útil en absoluto, pero tal vez aún no haya visto la luz :)
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 con el mismo propósito?
La razón es que StringBuffer
es seguro para subprocesos y StringBuilder
no lo es.
StringBuilder
es una nueva clase StringBuffer Api
y se introdujo JDK5
y siempre se recomienda si está trabajando en un entorno de un solo subproceso, ya que es muchoFaster
Para obtener detalles completos, puede leer http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
En java, String es inmutable. Al ser inmutable, 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, Stringbuilder se ejecuta más rápido. Puede aprender la diferencia entre String, StringBuilder y StringBuffer implementándolos.