5

I'm currently learning to program in Java, and I have a question about the unary incrementers listed in the title I haven't been able to find elsewhere. I just started playing around with them, and couldn't quite decide which one to use in a for loop because it seems the difference in behaviors between prefix(increment then evaluate) and postfix(evaluate then increment) wouldn't apply in a for statement. So I tried both, and both worked. This worries me, because I want to use them the way they're meant to be used.

So my question is, are they truly interchangeable in incrementing a for loop, or is there some obscure problem I'll run into down the road using one vice the other?

I decided to time them (below), and ++x definitely runs faster than x++, but I have no idea why. Can anyone expand on that?

Thanks!

public class PlusPlus
{
    public static void main(String[] args)
    {
        long startTime1, startTime2, endTime1, endTime2;
        final double COUNT = 100000000;

        //times x++ incrementing
        startTime1 = System.currentTimeMillis();
        for(int x = 0; x < COUNT; x++);
        endTime1 = System.currentTimeMillis();
        System.out.println("x++ loop: " + (endTime1 - startTime1) + " milliseconds");

        //times ++x incrementing
        startTime2 = System.currentTimeMillis();
        for(int x = 0; x < COUNT; ++x);
        endTime2 = System.currentTimeMillis();
        System.out.println("++x loop: " + (endTime2 - startTime2) + " milliseconds");
    }
}
brock
  • 365
  • 1
  • 3
  • 11
  • 3
    I would _not_ trust that this program actually tells you which version is "faster" in the general case. – Louis Wasserman Sep 25 '13 at 23:17
  • 2
    possible duplicate of [Is ++x more efficient than x++ in Java?](http://stackoverflow.com/questions/12396740/is-x-more-efficient-than-x-in-java) – hrv Sep 25 '13 at 23:19
  • The main question was which is preferable in incrementing a for loop, not which is more efficient. I'm still very new to programming, and I come across obscure bugs all the time using a particular operator or method that works in one situation and not another. Just want to make sure I'm using it correctly. Thanks to everyone for your responses. – brock Sep 25 '13 at 23:30

4 Answers4

5

Your test isn't going to yield much in terms of knowing how the performance works. Because of the nature of the JVM, writing performance tests is difficult enough that entire frameworks are written for benchmarking.

To really understand what the difference is, you should decompile the code using javap.

I compiled this class:

public class MyClass {

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++)
            System.out.println(i);
    }
}

And ran javap -c MyClass to get this for main:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   bipush  20
   5:   if_icmpge       21
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  iload_1
   12:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   15:  iinc    1, 1
   18:  goto    2
   21:  return

}

I then did it again, but this time, used the pre-increment:

for (int i = 0; i < 20; ++i)

And I got this for javap:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   bipush  20
   5:   if_icmpge       21
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  iload_1
   12:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   15:  iinc    1, 1
   18:  goto    2
   21:  return

}

Notice anything? Particularly that they're exactly the same?

This is because Java optimized away the extra instructions around pre-loading versus post-loading the value. It recognizes that the instruction it generates to load the variable into a register (iload_# in javap output) is redundant and unnecessary and optimizes it out.

In programming, there's a term called premature optimization. This is where you optimize something that you don't really need to optimize because it could cause performance problems. All you're really doing is making your code more complex. Most "good" programmers (if such a being exists) avoid this and instead focus on writing code that's maintainable. If the maintainable code doesn't perform well, then it's optimized. I remember reading a response here on SO about the 3 different levels of programmers (beginner, intermediate, advanced) and how to tell (loosely) which category you fall into. I'll see if I can find it.

Edit: Quick explanation of my answer: javac compiles your .java files into bytecode. Bytecode is stored in .class files. The bytecode tells the JVM step-by-step how to accomplish something. For example, iinc 1, 1 tells it to take variable 1 (in this case, this is i) and increment it by 1. iload_1 tells it to take variable 1 and load it so it can be used, usually in an operation or a method call. For example, this:

   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  iload_1
   12:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V

means "get System.out and load it, then load variable #1 (i), now call method #3." When we call the method, the first thing loaded (System.out) is our "target", meaning call the method on that guy. Every other thing loaded in is passed as an argument. In this case, that means i. So those three lines represent the line System.out.println(i). The bytecode just tells Java what to do to actually do that.

The fact that there is no iload_1 in the decompiled code for both pre- and post-increment means that Java optimized it away since it realized it wasn't going to actually be used. In both cases, it just did iinc without an iload, which is exactly contrary to most of the other answers in this thread.

Brian
  • 17,079
  • 6
  • 43
  • 66
  • Thank you Brian, but all that is way over my head. I'm still very much a beginner. – brock Sep 27 '13 at 11:32
  • Also, it looks like you used the post-increment for both decompiles, which might explain why they both look the same. – brock Sep 27 '13 at 11:41
  • Thanks for the explanation. Now I'm confused though as to why when I set a start and end time like above before and after my loops, the one with the post increment always takes longer. Not that it matters from a practical standpoint. Just curious about what's going on under the hood that makes it seem to be inconsistent with your explanation. – brock Oct 03 '13 at 16:27
  • @brock Your testing will never be as accurate as using an actual benchmark tool like [caliper](https://code.google.com/p/caliper/). Until code is executed several thousand times, the JVM will interpret the bytecode rather than compile it to native machine language. This means that your test is probably inaccurate. The garbage collector could also run during your test, which could also skew the results. Benchmarking tools take all this into consideration, so unless you're using a benchmarking tool, you shouldn't trust your results from your own timing code. – Brian Oct 03 '13 at 22:50
3

As far as efficiency goes, we are splitting hairs. Even when you really try to optimize your down to the metal code, x++ vs ++x isnt super important. However, yes, ++x is technically faster because x++ must store the old value of x, increment it, and then return the old value. ++x does not need to store it.

The big reason to worry about ++x vs x++is really all about the return value. Sometimes you want to have one over the other.

David says Reinstate Monica
  • 19,209
  • 22
  • 79
  • 122
2

In order to return the "old" value, the x++ operator needs to make a temporary copy of the old value, causing a slight performance decrease.

In your for loop, you're not making use of the value returned, so ++x is preferable.

Tom
  • 2,369
  • 13
  • 21
  • 2
    The compiler should be able to tell that's not needed here and optimize the dead code away. – Joel Sep 25 '13 at 23:19
1

++x: increment x; the value of the overall expression is the value after the increment

x++: increment x; the value of the overall expression is the value before the increment

Consider these two sections:

int x = 0;
System.out.println(x++); // Prints 0
// x is now 1

int y = 0;
System.out.println(++y); // Prints 1
// y is now 1

I personally try to avoid using them as expressions within a larger statement - I prefer standalone code, like this:

int x = 0;
System.out.println(x); // Prints 0
x++;
// x is now 1


int y = 0;
y++;
System.out.println(y); // Prints 1
// y is now 1

Here I believe everyone would be able to work out what's printed and the final values of x and y without scratching their heads too much.

There are definitely times when it's useful to have pre/post-increment available within an expression, but think of readability first.

sunysen
  • 2,265
  • 1
  • 12
  • 13