Apex: Anatomy of a Traditional For Loop

If you’re just learning how to code in Apex (or any language, for that matter), one of the most important loops you’ll learn to use is the traditional for loop. From iterating over lists to creating test data, you’ll use it often when coding so it’s worth investing the time to fully understand how it works early in your training.

In Apex, it looks something like this:

for (Integer i = 0; i < 5; i++) {
    Sytem.debug('i = ' + i);
}

And here’s a more generic way of looking at it:

for (expression1; expression2; expression3) {
    // code block
}

And here’s how it’s presented in Salesforce documentation:

for (init_stmt; exit_condition; increment_stmt) {
    code_block
}

So, let’s break down the traditional for loop with examples:

Initialization Statement

for (Integer i = 0; i < 5; i++) {
    Sytem.debug('i = ' + i);
}

The first expression is the initialization statement. In the example above, it’s Integer i = 0.

This is where we initialize any variables that are used in the loop. Often, we’re just initializing the variable i, an integer — the same one that will be incremented and evaluated with each loop.

By convention, we typically use the letter i, but you can use any letter or variable name. But between you and me, stick with i since it makes you look like a perfectly boring but competent coder. (Anything else and we’ll quickly question the rest of your code.)

Also, it does not need to be initialized to zero (for instance, it could be 1 or 111). But when working with lists (arrays), we start with zero because index 0 is where the first item is located:

List<String> favoriteColors = new List<String>{'red', 'green', 'yellow', 'blue'};
System.debug('These are my favorite colors: ');
for (Integer i = 0; i < favoriteColors.size(); i++) {
    System.debug(favoriteColors[i]);
}

It’s also important to know that we can initialize more than one variable in the first expression. For instance, using the example above, we could create a new variable n to represent the size of favoriteColors like so:

List<String> favoriteColors = new List<String>{'red', 'green', 'yellow', 'blue'};
System.debug('These are my favorite colors: ');
for (Integer i = 0, n = favoriteColors.size(); i < n; i++) {
    System.debug(favoriteColors[i]);
}

Why would we do this? Becuase it makes our code more efficient. Instead of calling the size() method on favoriteColors with every loop iteration (forcing it to calculate its size over and over again), we can do it once and be done with it.

The last thing I want you to notice is that we use a comma to separate variables in the first expressions and a semicolon to separate one expression from the other. (Without a doubt, at some point you’ll mistakenly use a comma to separate expressions and get a cryptic error message. It will then take you 10 minutes to realize you need to replace them with semicolons. Ask me how I know.)

Finally, the initialization statement is executed first and only once at the start of the loop.

Entry/Exit Condition

for (Integer i = 1; i <= 5; i++) {
System.debug('i = ' + i);
}

The Apex Developer Guide refers to the second expression as the exit condition. I think it makes more sense to think of it as the entry condition. As long as the expression evaluates to true, the next iteration of the code (found between the loop’s curly braces) will run. When it evaluates to false, the loop terminates.

Above, our entry/exit condition is i <= 5.

This expression gets evaluated right after the initialization statement. This means the loop will not run if the expression immediately evaluates to false.

It also gets evaluated right after the increment statement (but we’ll talk more about that later).

Following the example below, as long as i is less than or equal to 5 the next loop iteration is executed:

It’s also worth pointing out that you can include multiple boolean statements for evaluation, joining them with the && or || logical operators:

Boolean runLoop = true;
for (Integer i = 1; i <= 5 && runLoop; i++) {
System.debug('i = ' + i);
}

Above, as long as the entire expression evaluates to true, the loop will run.

Finally, notice we’re using <= instead of just < (as we did in the very first example). That’s because, instead of iterating over a list (and needing an index to start at 0), we simply need to count from 1 to 5. For this reason, we start at 1 and make sure i <=5 when evaluated.

If we did this with a list, we’d get a list-index-out-of-bounds error whenever our code attempted to use an index equal to or larger than the size of our list (as we see in this example):

There are two ways to fix this. The easiest is to simply remove the equal sign and leave it as i < eastCoastCities.size(). The expression 4 < 4 would then evaluate to false when i = 4, terminating the loop.

The other way is to subtract 1 from the list size like this: i <= eastCoastCities.size() – 1. I would suggest going with the first option since it simply looks cleaner.

Increment Statement

for (Integer i = 0; i < 5; i++) {
    Sytem.debug('i = ' + i);
}

The last expression is the increment statement. Most of the time, it will be i++, just like we see above.

Here we’re using the increment operator (++) to add 1. That said, we could use any math operator to change our variable. For instance, if we wanted to decrement by 1, we could use the decrement operator (– –). Or we could add by twos, i += 2, or multiply by twos, i *= 2.

Whatever you choose to do, you just need to make sure that your variable changes in some way so that your entry/exit condition eventually evaluates to false, terminating the loop.

Finally, immediately after the increment statement runs, the exit/entry condition is evaluated. If it evaluates to true, the next iteration of the code block is run. If it evaluates to false, the loop terminates before running the code block again.

Code Block

for (Integer i = 0; i < 5; i++) {
    Sytem.debug('i = ' + i);
}

Obviously, this is where your code goes. It will repeat the number of times your loop runs. Remember, after the initialization statement, the entry/exit condition is evaluated, so it’s possible this code block will never run if the condition immediately evaluates to false.

Break

// This code finds the first item in the list that starts with the letter 'p'
List<String> favoriteFoods = new List<String>{'oranges', 'curry', 'peanuts', 'spinach', 'pickles'};
for (Integer i = 1; i < favoriteFoods.size(); i++){
    String item = favoriteFoods[i];
    if (item.left(1) == 'p'){
        System.debug('First item that starts with \'p\': ' + item);
        break;
    }
}

We use the break jump statement when we want to terminate the loop early, before the entry/exit condition has a chance to evaluate to false. This is used when your loop has accomplished what it was set out to do but would continue to run otherwise.

In the example above, after finding the first item that starts with the letter ‘p’, there’s no reason to continue, so we use break to terminate the loop.

Continue

// This code prints the name of any item that starts with the letter 'p'
List<String> favoriteFoods = new List<String>{'oranges', 'curry', 'peanuts', 'spinach', 'pickles'};
for (Integer i = 1; i < favoriteFoods.size(); i++){
    String item = favoriteFoods[i];
    if (item.left(1) != 'p'){
        continue;
    }
    System.debug(item);
}

We use the continue jump statement when we want to abruptly stop the current iteration of the loop and move to the next one. This means the code stops where continue appears and it jumps to the increment statement. Above, we want to print out any item that starts with the letter ‘p’. Therefore, if the item doesn’t start with ‘p’ we want to jump ahead to the next item in the list instead of printing it out.

I admit, this is not a great example of using continue since this code could be better written without it — but hopefully it conveys how it works.

Did you learn something new? Let me know below! Did I overlook an important aspect of traditional for loops? Educate me by leaving a comment. Thanks!

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.