Grismak
Grismak

Reputation: 316

Use of StringBuilder vs String in Java

I have a loop thats constantly setting new values to a few string and looking into it, i thought that i could improve it. At first it was easy (this is how it actually looks) but i am looking for a way to avoid doing that lot of "ToString" and then resetting that string to "".

private void obtenerProfCita(JSONArray catalogoDatos) {
        String areaConsumer = "";
        String resourceConsumer = "";
        String activityConsumerid = "";
        for(int i = 0; i < catalogoDatos.length(); i++) {
            areaConsumer = catalogoDatos.getJSONObject(i).get("area_consumerid").toString();
            resourceConsumer = catalogoDatos.getJSONObject(i).get("resource_consumerid").toString();
            activityConsumerid = catalogoDatos.getJSONObject(i).get("activity_consumerid").toString();
            if(StringUtils.isNotBlank(areaConsumer) && StringUtils.isNotBlank(resourceConsumer) && StringUtils.isNotBlank(activityConsumerid)) {
                log.error("REFERENCIA TUOTEMPO:\nModulo: " + i + "\nCONSUL: " + areaConsumer + "\nIDPROF: " + resourceConsumer);
                TuotempoDAO.guardarActivityId(catalogoDatos.getJSONObject(i));//Guardar en BBDD el Activity_ID
            }
            areaConsumer = "";
            resourceConsumer = "";
        }
    }

As you can see, is a basic for loop but taking in account that the JSONArray is quite big, i was looking for a way to use StringBuilders or StringBuffers and avoid the "ToStrings" in the JSON array.

Actual code with stringBuilders:

private void obtenerProfCita(JSONArray catalogoDatos) {
        StringBuilder areaConsumer = new StringBuilder();
        StringBuilder resourceConsumer = new StringBuilder();
        StringBuilder activityConsumerid = new StringBuilder();
        for(int i = 0; i < catalogoDatos.length(); i++) {
            areaConsumer.append(catalogoDatos.getJSONObject(i).get("area_consumerid").toString());
            resourceConsumer.append(catalogoDatos.getJSONObject(i).get("resource_consumerid").toString());
            activityConsumerid.append(catalogoDatos.getJSONObject(i).get("activity_consumerid").toString());
            if(StringUtils.isNotBlank(areaConsumer) && StringUtils.isNotBlank(resourceConsumer) && StringUtils.isNotBlank(activityConsumerid)) {
                log.error("REFERENCIA TUOTEMPO:\nModulo: " + i + "\nCONSUL: " + areaConsumer + "\nIDPROF: " + resourceConsumer);
                TuotempoDAO.guardarActivityId(catalogoDatos.getJSONObject(i));//Guardar en BBDD el Activity_ID
            }
            areaConsumer.setLength(0);
            resourceConsumer.setLength(0);
        }
    }

Also i have doubts about how efficient is to use StringBuilder instead of String, if someone could explain it to me it would be great.

EDIT. Thanks to OH GOD SPIDERS below, i have improved a little my code. here it´s how it looks right now:

private void obtenerProfCita(JSONArray catalogoDatos) {
        StringBuilder areaConsumer = new StringBuilder();
        StringBuilder resourceConsumer = new StringBuilder();
        StringBuilder activityConsumerid = new StringBuilder();
        for(int i = 0; i < catalogoDatos.length(); i++) {
            areaConsumer.append(catalogoDatos.getJSONObject(i).get("area_consumerid"));
            resourceConsumer.append(catalogoDatos.getJSONObject(i).get("resource_consumerid"));
            activityConsumerid.append(catalogoDatos.getJSONObject(i).get("activity_consumerid"));
            if (StringUtils.isNotBlank(areaConsumer) 
                    && StringUtils.isNotBlank(resourceConsumer) 
                      && StringUtils.isNotBlank(activityConsumerid)) {
                log.error("REFERENCIA TUOTEMPO:\nModulo: " + i + "\nCONSUL: " + areaConsumer + "\nIDPROF: " + resourceConsumer);
                TuotempoDAO.guardarActivityId(catalogoDatos.getJSONObject(i));//Guardar en BBDD el Activity_ID
            }
            areaConsumer.setLength(0);
            resourceConsumer.setLength(0);
            activityConsumerid.setLength(0);
        }
    }

Any help is appreciatted

EDIT2:

Thank you for all the help, i will modify my code taken in account the last comment and answers.

Upvotes: 0

Views: 432

Answers (3)

SkyAttack
SkyAttack

Reputation: 11

stringbuilder create one object but for '+',every time you use will create a new Stringbuilder object and use tostring() once,as the byteCodes show

for test1,loop body contains: one StringBuilder Object init,two append method,one tostring method

for test2,loop body contains: one append method

public class Test6 {
    String test1(){
        String a = "";
        for (int i = 0; i < 10; i++) {
            a += "a";
        }
        return a;
    }
    String test2(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            sb.append("a");
        }
        return sb.toString();
    }
}

test1

 0 ldc #2
 2 astore_1
 3 iconst_0
 4 istore_2
 5 iload_2
 6 bipush 10
 8 if_icmpge 37 (+29)
11 new #3 <java/lang/StringBuilder>
14 dup
15 invokespecial #4 <java/lang/StringBuilder.<init> : ()V>
18 aload_1
19 invokevirtual #5 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
22 ldc #6 <a>
24 invokevirtual #5 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
27 invokevirtual #7 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
30 astore_1
31 iinc 2 by 1
34 goto 5 (-29)
37 aload_1
38 areturn

test2

 0 new #3 <java/lang/StringBuilder>
 3 dup
 4 invokespecial #4 <java/lang/StringBuilder.<init> : ()V>
 7 astore_1
 8 iconst_0
 9 istore_2
10 iload_2
11 bipush 10
13 if_icmpge 29 (+16)
16 aload_1
17 ldc #6 <a>
19 invokevirtual #5 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
22 pop
23 iinc 2 by 1
26 goto 10 (-16)
29 aload_1
30 invokevirtual #7 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
33 areturn

Upvotes: 1

Thomas Kl&#228;ger
Thomas Kl&#228;ger

Reputation: 21435

Your loop is not appending to the strings and therefore using StringBuilder gives no performance improvements.

I would only do two things:

  • move the declaration of the variables into the loop
  • only fetch catalogoDatos.getJSONObject(i) once and store that reference in a local variable

This gives the following code:

private void obtenerProfCita(JSONArray catalogoDatos) {
    for (int i = 0; i < catalogoDatos.length(); i++) {
        JSONObject o = catalogoDatos.getJSONObject(i);
        String areaConsumer = o.get("area_consumerid").toString();
        String resourceConsumer = o.get("resource_consumerid").toString();
        String activityConsumerid = o.get("activity_consumerid").toString();
        if (StringUtils.isNotBlank(areaConsumer) && StringUtils.isNotBlank(resourceConsumer) && StringUtils.isNotBlank(activityConsumerid)) {
            log.error("REFERENCIA TUOTEMPO:\nModulo: " + i + "\nCONSUL: " + areaConsumer + "\nIDPROF: " + resourceConsumer);
            TuotempoDAO.guardarActivityId(o);//Guardar en BBDD el Activity_ID
        }
    }
}

About the idea that StringBuilder.append() somehow works around the need for toString():

What do you think how StringBuilder.append() does append the string representation of an object?

Great surprise: it uses toString() internally.

Actually, if you look at the internals of StringBuilder.append(Object):

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

it calls String.valueOf(obj) which is

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Effectively the only difference between

stringBuilder.append(obj);

and

stringBuilder.append(obj.toString());

is that first version correctly handles the case where obj is null whereas in the second case it will throw a NullPointerException.

Upvotes: 3

kutschkem
kutschkem

Reputation: 8163

The difference, when concatenating lots of Strings in a loop is that:

  • concatenating Strings in a loop with e.g. += creates lots of new intermediate Strings
  • StringBuilder doesn't, it collects all the Strings, then builds a new one at the end (actually I think it has an array/array list of chars that gets filled, but the details don't matter here). Less memory used, less copying characters around.

Doesn't matter much for small amounts of Strings, but if your array is big it should be noticeable.

Upvotes: 3

Related Questions