2

Method 1

int[] arr = new int[10];
for(int i = 0; i < arr.length; i++) {
    if(i % 2 == 0)
       // do stuff
    else
       // do stuff
}

Method 2

int[] arr = new int[10];
boolean flag = true;
for(int i = 0; i < arr.length; i++) {
    if(flag) {
       // do stuff
       flag = false;
    }
    else {
       // do stuff
       flag = true;
    }
}

Method 3

int[] arr = new int[10];
for(int i = 0; i < arr.length; i++) {
    if((i & 1) == 1)
       // do stuff
    else
       // do stuff
}

Method 4

int[] arr = new int[10];
for(int i = 0; i < arr.length; i+=2) {
   // do stuff for even numbers
}
for(int i = 1; i < arr.length; i+=2) {
   // do stuff for odd numbers
}

When switching from Method 1 to Method 3, a guy got 66% performance boost.

What are the merits and demerits of choosing a method between 2 and 3, in a production environment with a big team?

Edit

Which is the best method, without sacrificing too much readability when you have distributed teams?

Nick Warke
  • 91
  • 6
  • I don't like method 2, because what would happen if, later on, someone accidentally modifies the `flag`? Methods 1 and 3 on the other hand check the oddness of the actual number directly. – Tim Biegeleisen Dec 15 '16 at 07:53
  • 7
    Who cares? You only get a 66% performance boost if you're not doing anything in branches of the if statement. Any optimization like this is - if it really works - is highly dependent on the exact version of the JVM, the exact operating system, machine configuration (CPU's, caches, etc) etc. that you run it on. And it's not likely to affect the overall performance of your application in the vast majority of applications. [Premature optimization is the root of all evil](http://wiki.c2.com/?PrematureOptimization) , as they say. – Erwin Bolwidt Dec 15 '16 at 07:54
  • *in a production environment with a big team?* why is this even relevant? – Scary Wombat Dec 15 '16 at 07:56
  • 1
    Note that the article you quote with the 66% performance boost is about ActionScript, which is a totally different language with a totally different runtime than Java. The fact that this one guy got this result with ActionScript does not mean the same holds for Java. – Jesper Dec 15 '16 at 08:01
  • 1
    I think the biggest effect this could have in a production environment with a big team is that you'd be getting fired for obvious lack of skill/experience/understanding. – Kayaman Dec 15 '16 at 08:02
  • @ScaryWombat I hope the Edit answers your question – Nick Warke Dec 17 '16 at 06:42
  • @Kayaman That is not possible, as I am a student. – Nick Warke Dec 17 '16 at 06:43

1 Answers1

3

If performance is what you want, I would bet my money on this:

    for(int i = 0; i < arr.length; i+=2) {
        // do even stuff
    }
    for(int i = 1; i < arr.length; i+=2) {
        // do odd stuff
    }

That way you can just skip the whole if-else part. And it is way more as fast as the "and" version. Let me show you; here we've got 4 different implementations of the same method:

private static long withModulus(int[] arr) {
    long elapsedTime = System.nanoTime();
    for(int i = 0; i < arr.length; i++) {
        List list;
        if ((i % 2) == 0) {
            list = new ArrayList<>();
            list.add(new Object());
        } else {
            list = new LinkedList<>();
            list.add(new Object());
        }
    }
    return (System.nanoTime() - elapsedTime);
}

private static long withFlag(int[] arr) {
    long elapsedTime = System.nanoTime();
    for(int i = 0; i < arr.length; i++) {
        List list;
        boolean flag = true;
        if (flag) {
            list = new ArrayList<>();
            list.add(new Object());
            flag = false;
        } else {
            list = new LinkedList<>();
            list.add(new Object());
            flag = true;
        }
    }
    return (System.nanoTime() - elapsedTime);
}

private static long withAnd(int[] arr) {
    long elapsedTime = System.nanoTime();
    for(int i = 0; i < arr.length; i++) {
        List list;
        if ((i & 1) == 1) {
            list = new ArrayList<>();
            list.add(new Object());
        } else {
            list = new LinkedList<>();
            list.add(new Object());
        }
    }
    return (System.nanoTime() - elapsedTime);
}

private static long withTwoLoops(int[] arr) {
    long elapsedTime = System.nanoTime();
    for(int i = 0; i < arr.length; i+=2) {
        List list;
        list = new ArrayList<>();
        list.add(new Object());
    }
    for(int i = 1; i < arr.length; i+=2) {
        List list;
        list = new LinkedList<>();
        list.add(new Object());
    }
    return (System.nanoTime() - elapsedTime);
}

And now for the timing part:

public static void main(String[] args) {
    int[] arr = new int[10000000];
    // Warm up
    withModulus(arr);
    withFlag(arr);
    withAnd(arr);
    withTwoLoops(arr);
    // Timing
    int iterations = 100;
    long meanModulus = 0, meanFlag = 0, meanAnd = 0, meanTwoLoops = 0;
    for (int i = 0; i < iterations; i++) {
        meanModulus += withModulus(arr);
    }
    for (int i = 0; i < iterations; i++) {
        meanFlag += withFlag(arr);
    }
    for (int i = 0; i < iterations; i++) {
        meanAnd += withAnd(arr);
    }
    for (int i = 0; i < iterations; i++) {
        meanTwoLoops += withTwoLoops(arr);
    }
    System.out.println("Modulus: "+(meanModulus/iterations)+" ms");
    System.out.println("Flag: "+(meanFlag/iterations)+" ms");
    System.out.println("And: "+(meanAnd/iterations)+" ms");
    System.out.println("Two loops: "+(meanTwoLoops/iterations)+" ms");
}

Results:

Modulus: 82331604 ms
Flag: 96305740 ms
And: 80845864 ms
Two loops: 79633999 ms

You can try with different array sizes, but for anything bigger than 10000 the two-loops option is the fastest.
After many different runs and tests, some times the "and" version is fastest, some times the "two loops" is. Even the "modulus" version came up as fastest in one of the tests. In production, it will mostly depend on what you do inside the loop, not on the condition itself.

walen
  • 7,103
  • 2
  • 37
  • 58
  • 1
    Not that the question deserves any answers, but here's some reading for you: http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – Kayaman Dec 15 '16 at 09:41
  • Thanks for the reading material! I was already on the process of making the code run the methods several times and take the mean to get a more reliable timing. I didn't know about `nanoTime()`, though! Regarding JMH, I have it on my "to learn" list, but honestly I didn't feel like downloading and learning to use it right now (on top of writing the answer). I'll have a look at it as soon as I can :) – walen Dec 15 '16 at 10:23
  • @NickWarke You do realize that your question is completely irrelevant, right? Testing a do-nothing loop for speed is a waste of time. Let's say you get an internship and start writing the "fastest" loops. Any competent programmer would ask you why you write them in such an odd way, and if you said "because it's faster", you'll be sure to get a talking to. – Kayaman Dec 19 '16 at 08:00