1

I am new to Java.

At first, I was testing the performance on String and StringBuilder in different cases.

However, I discovered that same code compiled by javac and eclipse performed differently.

I read about that String concatenation is actually using StringBuilder but why is that performance has so big difference in this case while String is 1.5x faster than StringBuilder.

Here is my testing code:

public class StringTest {
    public StringTest() {
        boolean flag = true;
        int code = 10001, type = 1;

        long time = System.nanoTime();
        for (int i = 0; i < 10000000; ++i) {
            String msg = Long.toString(i * 1000000000);
            stringHandler(code, type, flag, msg);
        }
        System.out.println("Took " + (System.nanoTime() - time) + " ns by String");

        time = System.nanoTime();
        for (int i = 0; i < 10000000; ++i) {
            String msg = Long.toString(i * 1000000000);
            stringBuilderHandler(code, type, flag, msg);
        }
        System.out.println("Took " + (System.nanoTime() - time) + " ns by StringBuilder");
    }

    public String stringBuilderHandler(int code, int type, boolean flag, String msg) {
        StringBuilder sb = new StringBuilder();

        sb.append("{\"bool\":").append(flag).append(",")
                .append("\"code\":").append(code).append(",")
                .append("\"type\":").append(type).append(msg).append("}");

        return sb.toString();
    }

    public String stringHandler(int code, int type, boolean flag, String msg) {
        String str = "{\"bool\":";
        str += flag;
        str += ",";
        str += "\"code\":";
        str += code;
        str += ",";
        str +=  "\"type\":";
        str += type;
        str += msg;
        str += "}";
        return str;
    }

    public static void main(String[] args) {
        StringTest st = new StringTest();
    }
}

Using javac 1.8:

Took 1066623964 ns by String
Took 1540007855 ns by StringBuilder

Using Eclipse:

Took 4282720864 ns by String
Took 1709934263 ns by StringBuilder
Walter
  • 11
  • 2
  • 1
    You can decompile the code using `javap -c` and see what the bytecode looks like in both cases. – Jesper May 25 '15 at 17:11
  • @Jesper Thanks for your advice. I noticed some differences that the bytecode compiled by eclipse invoked String.valueOf while javac didn't. But as I said, I am new to Java, I don't really understand how would this matters so much to the performance. I would be very thankful if you can give me further explanation. – Walter May 25 '15 at 17:33
  • do you use the same JVM to execute the code? which JVM? – ZhongYu May 25 '15 at 18:39
  • @bayou.io Yes, it's the same, jre1.8.0_45 and I only have this environment in my os. – Walter May 25 '15 at 18:48
  • it won't be surprising if oracle's jvm optimizes better for oracle's javac output - not for nefarious reasons. jvm needs to look at the instruction pattern, guess what it does, and assume a strategy that's likely optimal. – ZhongYu May 25 '15 at 19:59

1 Answers1

4

There is a huge problem in your stringBuilderHandler and it's that you're creating a new instance of StringBuilder on every call, when you should reuse the same instance to see the concatenation. Do similar in stringHandler: reuse the same String variable, and then you will notice the difference. Also, you should follow the rules of a proper micro benchmark as shown here: How do I write a correct micro-benchmark in Java? or use a micro benchmark framework like Caliper or JMH.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • Yes, I am aware of the problem but I need to create the instance inside the method because I was implementing a handler which will be called by different threads and my fellow mentioned bad performance of StringBuffer declared outside the method. As I said, I am new to Java so I don't really know how to use those framework but I would like to try it. It's the different behaviors by this two make me so confused. – Walter May 25 '15 at 17:25
  • What's the use case you need to solve? Looks more like you need to append content to then print it into a file or something. I would use a `BlockingQueue` rather than other synchronization techniques, and in the end empty the queue and concatenate its contents using `StringBuilder` once. Or maybe you only need a logging facility. – Luiggi Mendoza May 25 '15 at 17:35
  • @ Luiggi Mendoza Thanks for your reply. Actually I am doing json transmission over network and I used Netty as my network framework. – Walter May 25 '15 at 17:41
  • I still don't understand where you need to synchronize the string manipulation. This should be designed to be done atomically. I guess you're mixing questions here. I suggest you to post a new question explaining your current use case, express your specific design issue and ask for guidance to solve that problem there. This question is about String concatenation and that's the scope of this answer as well. – Luiggi Mendoza May 25 '15 at 17:43
  • The given code is just to test which one I should choose to use when I need to append string inside a method. Maybe it's a faulty design in network application? But my ultimate confusion here is the different behavior between eclipse and javac and it makes want to change my IDE because I found that NetBeans has no such problem. – Walter May 25 '15 at 17:51
  • Again (despite the IDE you use): I don't understand your ultimate problem. If you design your application in order that a single thread creates the String and uses it as your response, then it's ok (as it should be). If you have a specific programming question on why to synchronize several threads/resources to write into the same String for whatever purpose, post it as a new question. – Luiggi Mendoza May 25 '15 at 18:03
  • I am just wondering why same code would perform such a drastic difference(around 4x) between eclipse and javac while I read some previous article stated that eclipse compiler has better optimization. So is there big changes in latest javac make such a difference? or how can I change the performance in eclipse (maybe by filling some compile arguments)? and does/did anyone have similar issues? – Walter May 25 '15 at 18:16
  • And the answer is: you're measuring the results **WRONG**. Use a proper benchmark framework and write the cases in the right way, then you will obtain real results. – Luiggi Mendoza May 25 '15 at 18:17
  • But how could it be wrong, it's just a few line of string concatenation and I can clearly see the difference in execution time. Anyway, I would try a proper benchmark framework later. Thank you for your time. – Walter May 25 '15 at 18:21