Respuestas:
Diferencia de mutabilidad:
Stringes inmutable , si intenta alterar sus valores, otro objeto se crea, mientras que StringBuffery StringBuilderson mutables para que puedan cambiar sus valores.
Diferencia de seguridad del hilo:
La diferencia entre StringBuffery StringBuilderes que StringBufferes segura para subprocesos. Entonces, cuando la aplicación necesita ejecutarse solo en un solo hilo, entonces es mejor usarla StringBuilder. StringBuilderes más eficiente que StringBuffer.
Situaciones
Stringobjeto es inmutable.StringBuilderes lo suficientemente bueno.StringBufferporque StringBufferes sincrónico para que tenga seguridad de subprocesos.Stringscuando modificamos el valor, se crea otro objeto. ¿La referencia de objeto anterior se anula para que pueda ser recolectada por la basura GCo incluso se recolecta basura?
Stringwith StringBuilder?
Stringcuando una estructura inmutable es apropiada; obtener una nueva secuencia de caracteres de a Stringpuede 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).StringBuildercuando necesita crear una secuencia de caracteres mutable, generalmente para concatenar varias secuencias de caracteres juntas.StringBufferen 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:
Stringes una clase inmutable, no se puede cambiar.
StringBuilderes una clase mutable a la que se puede agregar, reemplazar o eliminar caracteres y, en última instancia, convertir a String
StringBufferes la versión original sincronizada deStringBuilder
Debería preferir StringBuilderen todos los casos en los que solo tiene un único hilo accediendo a su objeto.
Los detalles:
También tenga en cuenta que StringBuilder/Buffersno 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/Bufferobjetos 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/Bufferclases comienzan a crecer.
En Java String x = "A" + "B";utiliza un StringBuilderdetrás de escena. Entonces, para casos simples, no hay beneficio de declarar el suyo propio. Pero si está construyendo Stringobjetos 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 Stringva 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/Bufferen 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/Bufferun poco más de lo que crees que vas a necesitar si no sabes de inmediato qué tan grande Stringserá, 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/Buffercon a, Stringya 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/Buffereso 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 Stringse 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 StringListimplementació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 StringBuilderdel tamaño exacto que necesita y recorrer la lista y construir en la salida, incluso puede convertir esa StringBuildervariable 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), StringBuilderse 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)
Stringel compilador puede optimizar la concatenación ( usando el operador + ) para usar StringBuilderdebajo, 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 StringBuilderen 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.
StringBuilderconcatenació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, StringBuilderse 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
-------------------------------------------------- --------------------------------
synchronisedy esa es la razón .
Cuerda
El String classrepresenta 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, StringBufferes seguro para subprocesos, que StringBuilderno lo es.
Por lo tanto, en una situación en tiempo real cuando diferentes subprocesos acceden a él, StringBuilderpodría tener un resultado indeterminado.
Tenga en cuenta que si está utilizando Java 5 o más reciente, debe usarlo en StringBuilderlugar 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. LaStringBuilderclase 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 StringBufferes 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 StringBufferes seguro para subprocesos y StringBuilderno lo es.
StringBuilderes una nueva clase StringBuffer Apiy se introdujo JDK5y 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.