String, StringBuffer y StringBuilder

Por favor, dime una situación en tiempo real para comparar String , StringBuffer y StringBuilder .

Diferencia de mutabilidad:

String es inmutable , si intenta modificar sus valores, se crea otro objeto, mientras que StringBuffer y StringBuilder se pueden modificar para que puedan cambiar sus valores.

Diferencia de seguridad del hilo:

La diferencia entre StringBuffer y StringBuilder es que StringBuffer es seguro para subprocesos. Entonces, cuando la aplicación necesita ejecutarse solo en un solo hilo, entonces es mejor usar StringBuilder . StringBuilder es más eficiente que StringBuffer .

Situaciones:

  • Si su cadena no va a cambiar use una clase String porque un objeto 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 lo suficientemente bueno.
  • Si su cadena de caracteres puede cambiar, y se accederá desde múltiples hilos, use un StringBuffer porque StringBuffer es sincrónico, por lo que tiene seguridad de hilos.
  • Utiliza String cuando una estructura inmutable es apropiada; obtener una nueva secuencia de caracteres de un String puede acarrear una penalización de rendimiento inaceptable, ya sea en tiempo de CPU o memoria (la obtención de subcadenas es eficiente debido a que los datos no se copian, pero esto significa que una cantidad potencialmente mayor de datos puede permanecer asignada).
  • Utiliza StringBuilder cuando necesita crear una secuencia de caracteres mutable, generalmente para concatenar varias secuencias de caracteres juntas.
  • Utiliza StringBuffer en las mismas circunstancias que usaría StringBuilder , pero cuando los cambios en la cadena subyacente deben estar sincronizados (porque varios hilos 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 finalmente convertir a String StringBuffer es la versión sincronizada original de StringBuilder

Debería preferir StringBuilder en todos los casos donde solo tiene un único subproceso que accede 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 ser reasignada cada vez que se llena. Asegúrese y cree sus objetos StringBuilder/Buffer suficientemente grandes originalmente donde no tengan que .append() tamaño constantemente cada vez que se .append() .

El redimensionamiento puede volverse muy degenerado. Básicamente, reajusta el tamaño de la matriz de respaldo a 2 veces su tamaño actual cada vez que necesita expandirse. Esto puede ocasionar que se asignen grandes cantidades de RAM y no se usen cuando las clases StringBuilder/Buffer comienzan 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 el suyo. Pero si está creando objetos String que son grandes, digamos menos de 4k, entonces declara StringBuilder sb = StringBuilder(4096); es mucho más eficiente que la concatenación o usa el constructor predeterminado que solo tiene 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 se escribe 1 carácter más de 10k, se volverá a asignar y se copiará en una matriz de 20k. Entonces, inicializar lo alto es mejor que lo bajo.

En el caso de tamaño automático, en el 17º personaje, la matriz de respaldo se reasigna y se copia a 32 caracteres, en el 33º personaje esto vuelve a suceder y se puede reasignar y copiar la matriz en 64 caracteres. Puede ver cómo esto degenera a 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 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 grande de lo que piensas que necesitarás si no sabes de primera mano qué tan grande será el String pero puedes adivinar. Una asignación de un poco más de memoria de la que necesita va a ser mejor que muchas reasignaciones y copias.

También tenga cuidado al inicializar un StringBuilder/Buffer con String ya que solo asignará el tamaño de String + 16 caracteres, lo que en la mayoría de los casos solo iniciará el ciclo de reasignación de reasignación y 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 termina con una instancia de StringBuilder/Buffer que no creó y no puede controlar el constructor al que se llama, hay una manera de evitar el comportamiento de reasignar y copiar degenerado. Llame a .ensureCapacity() con el tamaño que desea para garantizar que su String resultante encajará.

Las alternativas:

Solo como una nota, si está 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 ArrayList y agregando contadores para rastrear el número de caracteres en cada .append() y otras operaciones de mutación de la lista, y luego anular .toString() para crear un StringBuilder del tamaño exacto que necesita y recorra la lista y construya el resultado, incluso puede hacer que StringBuilder una variable de instancia y “almacenar en caché” los resultados de .toString() y solo tiene que volver a generarlo cuando algo cambie.

Además, no te olvides de String.format() al String.format() una salida de formato fijo, que el comstackdor puede optimizar, ya que lo mejoran.

¿Te refieres a la 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 + "
" + " I saw your profile and got interested in you.
" + " I'm " + user.age + "yrs. old too"

StringBuilder

 String s = new StringBuilder().append.("Dear ").append( user.name ).append( "
" ) .append(" I saw your profile and got interested in you.
") .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 syntax es exactamente como con StringBuilder, los efectos difieren)

Acerca de

StringBuffer vs. StringBuilder

El primero está sincronizado y luego no.

Entonces, si lo invocas varias veces en un único 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 locking del hilo.

Por lo tanto, es recomendable utilizar StringBuilder (a menos que, por supuesto, tenga más de un hilo accediendo a él al mismo tiempo, lo que es raro)

String concatenación de String ( usando el operador + ) puede ser optimizada por el comstackdor para usar StringBuilder debajo, por lo tanto, ya no es algo de lo que preocuparse, en los viejos tiempos de Java, esto era algo que todos deberían evitar a toda costa, porque cada concatenación creó un nuevo objeto String. Los comstackdores modernos ya no hacen esto, pero aún así es una buena práctica usar StringBuilder en caso de que use un comstackdor “antiguo”.

editar

Solo para quién tiene curiosidad, esto es lo que el comstackdor hace 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."":()V 4: aload_0 5: new #2; //class java/lang/StringBuilder 8: dup 9: invokespecial #3; //Method java/lang/StringBuilder."":()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."":()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 31-53 son para la cadena llamada “constructor”

No hay diferencia, exactamente el mismo código se ejecuta para ambas cadenas.

 -------------------------------------------------- --------------------------------
                   String StringBuffer StringBuilder
 -------------------------------------------------- --------------------------------                 
 Área de almacenamiento |  Montón de stack constante Montón de stack 
 Modificable |  No (inmutable) Sí (mutable) Sí (mutable)
 Thread Safe |  Sí Sí No
  Rendimiento |  Rápido Muy lento Rápido
 -------------------------------------------------- --------------------------------

Familia de cuerdas

Cuerda

La String class representa cadenas de caracteres. Todos los literales de cadena en el progtwig Java, como "abc" se implementan como instancias de esta clase.

Los objetos de cadena son inmutables una vez que se crean no podemos cambiar. (Las cadenas son constantes )

  • Si se crea una Cadena usando el constructor o el método, esas cadenas se almacenarán en Heap Memory y SringConstantPool . Pero antes de guardar en el grupo, invoca el método intern() para verificar la disponibilidad del objeto con el mismo contenido en el grupo utilizando el método equals. Si String-copy está disponible en Pool, entonces devuelve la referencia. De lo contrario, el objeto String se agrega al grupo 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 a 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); } 
  • 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 con el nuevo operador. Por lo tanto, se almacenan en la memoria Heap.

  • Las instancias de StringBuilder no son seguras para su uso por múltiples hilos. 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 tienen métodos especiales como., replace(int start, int end, String str) e reverse() .

    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 utilizar String Class . Como parte de Generics, si desea Ordenar Comparable o comparar valores, vaya a String Class .

     //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable Set set = new TreeSet(); 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 por StringBuffer.

Además, StringBuffer es seguro para subprocesos, que StringBuilder no lo es.

Entonces, en una situación en tiempo real cuando diferentes subprocesos están accediendo a él, StringBuilder podría tener un resultado no determinista.

Tenga en cuenta que si está utilizando Java 5 o posterior, debe usar StringBuilder lugar de StringBuffer . De la documentación API:

A partir del lanzamiento JDK 5, esta clase ha sido complementada con una clase equivalente diseñada para ser usada por un solo hilo, StringBuilder . La clase StringBuilder 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 de varios subprocesos al mismo tiempo, por lo que la sincronización que realiza StringBuffer es casi siempre una sobrecarga innecesaria.

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 nada útil, pero tal vez aún no he 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 para el mismo propósito?

La razón es que StringBuffer es Thread safe y StringBuilder no lo es. StringBuilder es una nueva clase en StringBuffer Api y se introdujo en JDK5 y siempre se recomienda si trabajas en un entorno de subproceso único, 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/

En java, String es inmutable. Ser inmutables significa 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 funciona más rápido. Puede aprender la diferencia entre String, StringBuilder y StringBuffer al implementarlos.