2010-06-04 21 views

Respuesta

290

Mutabilidad Diferencia:

String es inmutable , si intenta alterar sus valores, otro objeto se crea, mientras que StringBuffer y StringBuilderson mutables para que puedan cambiar sus valores.

Diferencia de rosca con la seguridad:

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 la cadena no va a cambiar utilizar una clase String ya que 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 único hilo, usar un StringBuilder es suficiente.
  • Si su cadena puede cambiar, y se accederá desde múltiples hilos, use un StringBuffer porque StringBuffer es síncrono, por lo que tiene seguridad de hilos.
+11

Además, el uso de String para operaciones lógicas es bastante lento, y no se aconseja en absoluto, ya que la JVM convierte la cadena a StringBuffer en el bytecode. Se pierde una gran cantidad de sobrecarga convirtiendo de String a StringBuffer y luego de vuelta a String nuevamente. –

+2

Entonces en 'Cadenas' cuando alteramos el valor se crea otro objeto. ¿La referencia de objeto anterior está anulada, por lo que puede ser basura recogida por el 'GC' o incluso se recoge basura? –

+0

@PietervanNiekerk ¿Qué quiere decir con operaciones lógicas? – emlai

9

¿Quiere decir, para concatenación?

Ejemplo del mundo real: Desea crear una nueva cadena a partir de muchas otras.

Por ejemplo, para enviar un mensaje:

cadena

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, TH efectos e difieren)

Sobre

StringBuffer vs StringBuilder

El primero está sincronizado y más tarde no lo es.

Por lo tanto, si se invoca varias veces en un solo hilo (que es el 90% de los casos), se ejecutará StringBuildermucho más rápido, ya que no se detendrá para ver si se posee el bloqueo de rosca.

lo tanto, es recomendable utilizar StringBuilder (a menos que, por supuesto, usted tiene más de un hilo para acceder a ella, al mismo tiempo, lo cual es raro)

String concatenación (usando el operador +) puede ser optimizado por el compilador 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 creaba un nuevo objeto String. Los compiladores modernos ya no hacen esto, pero aún así es una buena práctica usar StringBuilder en lugar de usar un compilador "viejo".

edición

Sólo por que 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 

} 

líneas numeradas 5-27 son para la cadena llamada "literal"

Las líneas numeradas 31-53 son para la cadena denominada "constructor"

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

+2

este es un muy mal ejemplo. Inicializar StringBuilder con "Dear" significa que el primer .append() causará una reasignación y copia. Negar por completo cualquier eficacia que intente obtener a través de la concatenación "normal". Un mejor ejemplo sería crearlo con un tamaño inicial que contendrá todo el contenido de la Cadena final. –

+1

NO es una buena práctica usar un 'StringBuilder' para hacer una concatenación de cadenas en el lado derecho de la asignación. Cualquier buena implementación usará un StringBuilder detrás de las escenas como dices. Además, su ejemplo de '" a "+" b "' se compilará en un solo literal '" ab "' pero si utilizó 'StringBuilder' resultaría en dos llamadas innecesarias a' append() '. –

+0

@Mark No pretendía usar '" a "+" b "' pero decir qué era una * Concatenación de cadenas * sobre que lo cambio para que sea explícito. Lo que no dices 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 cuerda final (aprox). – OscarRyz

3

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 están accediendo a él, StringBuilder podría tener un resultado indeterminado.

44
  • Utiliza String cuando una estructura inmutable es apropiada; obtener una nueva secuencia de caracteres de String puede acarrear una penalización inaceptable del rendimiento, ya sea en tiempo de CPU o memoria (la obtención de subcadenas es eficiente en la CPU porque 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 utilizarí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).

Ver un ejemplo here.

+2

+1, respuesta concisa. – Dolph

+2

concisa, pero incompleta, omite la razón fundamental para utilizar StringBuilder/Buffer y es para reducir o eliminar la reasignación y copia de matriz del comportamiento de concatenación de cadena normal. –

+1

"Utiliza String cuando se trata de cadenas inmutables": no tiene sentido. Las instancias de String ARE son inmutables, por lo que tal vez el comentario debería decir "Use String cuando el uso de memoria debido a la inmutabilidad no importa". La respuesta aceptada cubre sus bases bastante bien. – fooMonster

26

Los fundamentos:

String es una clase inmutable, que no se pueden cambiar. StringBuilder es una clase mutable que puede ser anexados, caracteres reemplazados o eliminados y finalmente convertidos a un String StringBuffer es la versión sincronizada original de StringBuilder

Usted debe preferir StringBuilder en todos los casos donde se tiene una única que accede hilo tu objeto

Los detalles:

También tenga en cuenta que no son StringBuilder/Buffers magia, sólo tiene que utilizar una matriz como un objeto respaldo y que la matriz tiene que ser re-asignado, cuando cada vez que se llena. Asegúrese de crear sus objetos StringBuilder/Buffer suficientemente grandes originalmente donde no tengan que cambiarse de tamaño constantemente cada vez que se llame al .append().

El cambio de tamaño puede ser 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 escena. Entonces, para casos simples, no hay beneficio de declarar el suyo. 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 default constructor que tiene solo 16 caracteres. Si su String va a tener menos de 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 17mo carácter, la matriz de respaldo se vuelve a asignar 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 en lotes de reasignaciones y copias que es lo que realmente está tratando de evitar con StringBuilder/Buffer en primer lugar.

Esto es a partir del código fuente del 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 piensa que va a necesitar si usted no sabe lado de la derecha cuán grande será el String, pero usted puede 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 de inicialización de un StringBuilder/Buffer con un String como que sólo se asigna el tamaño de la cadena + 16 caracteres, que en la mayoría de los casos se acaba de iniciar el degenerada reasignación y copia de ciclo que se 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 no terminar con una instancia de StringBuilder/Buffer que no creó y no puede controlar el constructor que se llama, no es una manera de evitar los degenerados re-asignar y copiar el comportamiento . Llame al .ensureCapacity() con el tamaño que desea para asegurarse de que su String resultante encajará.

las alternativas:

Así como una nota, si usted está haciendo muy pesada String construcción y manipulación, hay una alternativa mucho más rendimiento orientada llama Ropes.

Otra alternativa, es la creación de un implemenation StringList por sub-clasificar a ArrayList<String>, y la adición de contadores para realizar un seguimiento del número de caracteres en cada .append() y otra mutación operaciones de la lista, a continuación, anular .toString() para crear un StringBuilder del tamaño exacto necesita recorrer la lista y crear el resultado, incluso puede hacer que StringBuilder sea 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 se olvide de String.format() al compilar una salida de formato fijo, que puede ser optimizada por el compilador, ya que lo hacen mejor.

+1

¿'String x =" A "+" B ";' realmente se compila para ser un StringBuilder? ¿Por qué no compilaría simplemente 'String x =" AB ";', solo debería usar un StringBuilder si los componentes no se conocen en tiempo de compilación. –

+0

podría optimizar las constantes de String, no recuerdo la última vez que descompilé el código de bytes, pero sí sé que si hay alguna variable allí, seguramente usará una implementación de StringBuilder. Puede descargar el código fuente JDK y descubrirlo usted mismo. "A" + "B" es un ejemplo artificial seguro. –

+0

Me preguntaba acerca de String.format(). Nunca he visto realmente que se use en proyectos. Por lo general, es el StringBuilder. Bueno, generalmente es "A" + "B" + "C" porque las personas son flojas;) Solía ​​usar siempre un StringBuilder, incluso si solo se concatenaban dos cadenas, porque en el futuro, tal vez se agregarían más cadenas. . Nunca utilicé String.format() principalmente porque nunca recordé el JDK que se introdujo. Veo que es JDK1.5, lo usaría a favor de las otras opciones. – jamiebarrow

3

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

partir de la versión JDK 5, esta clase se ha complementado con una clase equivalente diseñado para su uso por un solo hilo, StringBuilder. La clase StringBuilder generalmente se debe utilizar 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, es casi nunca se usan esto desde múltiples subprocesos al mismo tiempo, por lo que la sincronización que StringBuffer hace es casi siempre una sobrecarga innecesaria.

2

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 :)

2

En java, La cadena 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 and StringBuffer implementándolas.

3

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?

Motivo es que StringBuffer es Thread safe y StringBuilder no lo es. StringBuilder es una nueva clase de StringBuffer Api y se introdujo en JDK5 y siempre se recomienda si está trabajando en un entorno de un solo subproceso ya que es mucho Faster

Para una completa detalles se puede leer http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/

3
 
---------------------------------------------------------------------------------- 
        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 
---------------------------------------------------------------------------------- 
3

String Family

cadena

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. (cadenas son constantes)

  • Si se crea una cadena usando constructor o método entonces se almacenarán esas cadenas en memoria de la pila así como SringConstantPool. Pero antes de guardar en el grupo, invoca intern() método para verificar la disponibilidad de objetos 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); 
    } 
    
  • literales de cadena se almacenan en StringConstantPool.

    String onlyPool = "Yash"; 
    

StringBuilder y StringBuffer son secuencia mutable 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 un nuevo operador. Por lo tanto, se almacenan en la memoria Heap.

  • Las instancias de StringBuilder no son seguras para el uso de 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 proporciona la implementación de Appendable Interface.


Cuando usar que uno.

  • Si un no van a cambiar el valor cada vez, entonces es mejor usar String Class. Como parte de Generics, si desea ordenar Comparable<T> o comparar valores, vaya a 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 se van a modificar el valor cada vez que la marcha de StringBuilder que es más rápido que StringBuffer. Si varios hilos están modificando el valor, vaya por StringBuffer.

Cuestiones relacionadas