StringBuilder vs concatenación de cadenas en toString() en Java

Resuelto non sequitor asked hace 14 años • 20 respuestas

Dadas las 2 toString()implementaciones siguientes, cuál se prefiere:

public String toString(){
    return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}

o

public String toString(){
    StringBuilder sb = new StringBuilder(100);
    return sb.append("{a:").append(a)
          .append(", b:").append(b)
          .append(", c:").append(c)
          .append("}")
          .toString();
}

?

Más importante aún, dado que solo tenemos 3 propiedades, es posible que no haya diferencia, pero ¿en qué punto cambiarías de +concat a StringBuilder?

non sequitor avatar Oct 07 '09 22:10 non sequitor
Aceptado

La versión 1 es preferible porque es más corta y el compilador, de hecho, la convertirá en la versión 2 , sin diferencia alguna en el rendimiento.

Más importante aún, dado que solo tenemos 3 propiedades, es posible que no haga una diferencia, pero ¿en qué momento se cambia de concat a builder?

En el punto en el que estás concatenando en un bucle, suele ser cuando el compilador no puede sustituirlo StringBuilderpor sí mismo.

Michael Borgwardt avatar Oct 07 '2009 15:10 Michael Borgwardt

La clave es si estás escribiendo una única concatenación en un solo lugar o acumulándola a lo largo del tiempo.

Para el ejemplo que diste, no tiene sentido usar StringBuilder explícitamente. (Mire el código compilado para su primer caso).

Pero si está creando una cadena, por ejemplo, dentro de un bucle, utilice StringBuilder.

Para aclarar, suponiendo que enormeArray contiene miles de cadenas, codifique como este:

...
String result = "";
for (String s : hugeArray) {
    result = result + s;
}

Es una gran pérdida de tiempo y memoria en comparación con:

...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();
joel.neely avatar Oct 07 '2009 15:10 joel.neely

En la mayoría de los casos, no verá una diferencia real entre los dos enfoques, pero es fácil construir un peor escenario como este:

public class Main
{
    public static void main(String[] args)
    {
        long now = System.currentTimeMillis();
        slow();
        System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");

        now = System.currentTimeMillis();
        fast();
        System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
    }

    private static void fast()
    {
        StringBuilder s = new StringBuilder();
        for(int i=0;i<100000;i++)
            s.append("*");      
    }

    private static void slow()
    {
        String s = "";
        for(int i=0;i<100000;i++)
            s+="*";
    }
}

La salida es:

slow elapsed 11741 ms
fast elapsed 7 ms

El problema es que agregar += a una cadena reconstruye una nueva cadena, por lo que cuesta algo lineal a la longitud de sus cadenas (suma de ambas).

Entonces, a tu pregunta:

El segundo enfoque sería más rápido, pero menos legible y más difícil de mantener. Como dije, en tu caso específico probablemente no verías la diferencia.

Omry Yadan avatar Oct 07 '2009 15:10 Omry Yadan