Amber
Amber

Reputation: 1249

Local member is faster or instance member

The following code proves that method1 is faster than method2. Can anyone please comment what is the reason for such behavior.

class Trial {
        String _member;
        void method1() {
            for(int i=0;i<30480;i++) {
                _member += "test";
            }
        }
        void method2() {
            String temp="";
            for(int i=0;i<30480;i++) {
                temp += "test";
            }
            _member = temp;
        }

        public static void main(String args[]) {
            Trial t = new Trial();
            long startTime1 = System.currentTimeMillis();
            t.method1();
            long endTime1 = System.currentTimeMillis();
            long startTime2 = System.currentTimeMillis();
            t.method2();
            long endTime2 = System.currentTimeMillis();
            System.out.println(endTime1 - startTime1);
            System.out.println(endTime2 - startTime2);
        }
    }

Upvotes: 7

Views: 194

Answers (3)

cl-r
cl-r

Reputation: 1264

I've modified the number of test, but not the method, here with StringBuilder 2500 at 3000 time more fast!

class Trial {
    StringBuilder _member = new StringBuilder(243840);
    void method1() {
        for (int i = 0; i < 30480; i++) {
            _member.append("test");
        }
    }

    void method2() {
        final StringBuilder temp = new StringBuilder(243840);
        for (int i = 0; i < 30480; i++) {
            temp.append("test");
        }
        _member = temp;
    }
    public static void main(final String args[]) {
        long startTime1 = System.nanoTime();
        new Trial().method1();
        long endTime1 = System.nanoTime();
        long startTime2 = System.nanoTime();
        new Trial().method2();
        long endTime2 = System.nanoTime();
        System.out.println(endTime1 - startTime1);
        System.out.println(endTime2 - startTime2);
        System.out.println("------------------");
        startTime1 = System.nanoTime();
        new Trial().method1();
        endTime1 = System.nanoTime();
        startTime2 = System.nanoTime();
        new Trial().method2();
        endTime2 = System.nanoTime();
        System.out.println(endTime1 - startTime1);
        System.out.println(endTime2 - startTime2);
    }
}

The output:

method1 then method2 with += in MILLIisecond
5563
5844
............................................
5437
6344

method2 then method1 with += in MILLIisecond
4625
5969
------------------
6531
4891

=====================================================

method1 then method2 with StringBuilder in NANOsecond
3530337
2074286
------------------
2058641
1983493
.....................................................

method2 then method1 with StringBuilder in NANOsecond
3430883
1698819
------------------
2065626
2144406

So As @Andreas said it is not a good way to test performances.

Thing to point out : use StringBuilder with declared size (In Joshua Bloch's book Effective Java Item 51: Beware the performance of string concatenation)
- prefer method2() when it possible : the String[Builder] is déclared inside it, and not use outside

Upvotes: 0

Sazzadur Rahaman
Sazzadur Rahaman

Reputation: 7116

After warming up the jvm for some times, you will see that, method2 is faster than method1.

Here is my re-factored code:

class Trial {
String _member;

  void method1() {
    for (int i = 0; i < 30480; i++) {
        _member += "test";
    }
  }

  void method2() {
    String temp = "";
    for (int i = 0; i < 30480; i++) {
        temp += "test";
    }
    _member = temp;
  }

  public static void main(String args[]) {
    Trial t = new Trial();

    for (int i = 0; i < 10; i++) { //warm up jvm
        t.method1();
        t.method2();
    }

    t = new Trial();

    long startTime1 = System.currentTimeMillis();
    t.method1();
    long endTime1 = System.currentTimeMillis();
    long startTime2 = System.currentTimeMillis();
    t.method2();
    long endTime2 = System.currentTimeMillis();
    System.out.println(endTime1 - startTime1);
    System.out.println(endTime2 - startTime2);
  }
}

And here is the result:

----
2910
2894
----

But for actual benchmarking, you should run it for several times and observe the statistical behaviors and only then you can draw any conclusion!

Upvotes: 0

Andreas Fester
Andreas Fester

Reputation: 36630

The following code proves that method1 is faster than method2

No. It does not prove it.

It depends on many factors. When I run this code, I get

1403
1248

So in my environment, your code "proves" that method1 is slower than method2.

When doing benchmarking, you need to take care of effects like caching and JVM warmup.

See also

for more information.


I slightly refactored the main method:

...

static void doBenchmark() {
   Trial t = new Trial();

   long startTime1 = System.currentTimeMillis();
   t.method1();
   long endTime1 = System.currentTimeMillis();

   long startTime2 = System.currentTimeMillis();
   t.method2();
   long endTime2 = System.currentTimeMillis();

   System.out.println(endTime1 - startTime1);
   System.out.println(endTime2 - startTime2);
}

public static void main(String args[]) {

   for (int i = 0;  i < 20;  i++) {
      doBenchmark();
      System.out.println("----");
   }
}

This results in similar values for the first iteration of the for-loop, but then the results converge and do not differ significantly anymore:

1396
1133
----
1052
1070
----
688
711
----
728
726
----
715
709
----
...

Even, sometimes method1 seems faster and sometimes method2 - this is most likely due to measurement inaccuracy.

Upvotes: 12

Related Questions