PurkkaKoodari
PurkkaKoodari

Reputation: 6809

Is it more efficient to use a flag or an if clause?

In a Java loop, is it more efficient to use a boolean flag instead of an if statement?

Take a look at these two bits of code.

Using a flag:

public boolean isSomethingForAnyone() {
    boolean flag = false;
    for (Item item : listOfItems) {
        flag = flag || item.isSomething();
    }
    return flag;
}

Using an if statement:

public boolean isSomethingForAnyone() {
    for (Item item : listOfItems) {
        if (item.isSomething())
            return true;
    }
    return false;
}

The method with the if statement is of course faster if isSomething() return true on the first iteration. But, is it faster on average or does the branching slow it down enough that it is slower? Also, is the situation different if the loop is faster? Here I used a for-each loop for simplicity, which I believe is slower than iterating over an array with a counter.

Upvotes: 7

Views: 354

Answers (3)

selig
selig

Reputation: 4844

If you want to know which is 'faster' on your machine then run it.

If we want to know which takes more instructions to perform then we can look at the bytecode.

For the first method we get this (call javap -c)

Code:
   0: iconst_0      
   1: istore_1      
   2: getstatic     #2                  // Field listOfItems:Ljava/util/List;
   5: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
  10: astore_2      
  11: aload_2       
  12: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
  17: ifeq          50
  20: aload_2
  21: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
  26: checkcast     #6                  // class Item
  29: astore_3      
  30: iload_1       
  31: ifne          41
  34: aload_3       
  35: invokevirtual #7                  // Method Item.isSomething:()Z
  38: ifeq          45
  41: iconst_1      
  42: goto          46
  45: iconst_0      
  46: istore_1      
  47: goto          11
  50: iload_1       
  51: ireturn   

We're interested in the interior of the loop i.e. lines 29-46 (lines 11-26 are Iterator stuff). So about 10 instructions.

For the second method we get this:

 Code:
       0: getstatic     #2                  // Field listOfItems:Ljava/util/List;
       3: invokeinterface #3,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
       8: astore_1      
       9: aload_1       
      10: invokeinterface #4,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      15: ifeq          40
      18: aload_1       
      19: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      24: checkcast     #6                  // class Item
      27: astore_2      
      28: aload_2       
      29: invokevirtual #7                  // Method Item.isSomething:()Z
      32: ifeq          37
      35: iconst_1      
      36: ireturn       
      37: goto          9
      40: iconst_0      
      41: ireturn       

The lines of interest are 27-37. So 7 instructions.

From a numbers point of view the second method comes out on top (note that we assume that all stack operations take the same time to perform).

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500525

The two pieces of code aren't quite equivalent.

Even though you only call item.isSomething() as many times as you need to (contrary to my original answer), the first version still keeps trying to iterate over the rest of the collection.

Imagine an implementation of Item.isSomething() which modified the collection in which the item is found (if it returns true). At that point, the first piece of code would throw a ConcurrentModificationException assuming it's a "regular" collection - whereas the second piece of code would just return true.

Fundamentally, the second piece of code is more efficient: it only iterates through as much of the list as is required to determine the answer, instead of through everything. It may well be that the performance different is irrelevant - particularly if the collection is small - but that depends on the context.

Which you find more readable is a different matter - it's likely that the efficiency won't be significant, although that depends on the context. Personally I find the second version more readable as well as more efficient, so I'd always use it. (Well, I'd add braces around the body of the if statement, but that's all.)

Upvotes: 4

John Gardner
John Gardner

Reputation: 25126

are you doing this loop literally a billion times? if not, the difference is probably impossible to measure.

you could look at the generated bytecode and see exactly what is going on, but the compiler and jit and the vm itself would probably optimize away any differences anyway.

Upvotes: 0

Related Questions