Favor For-Each Over For Loops

 class​ LaunchChecklist {
 
  List<String> checks = Arrays.asList(​"Cabin Pressure"​,
 "Communication"​,
 "Engine"​);
 
  Status prepareForTakeoff(Commander commander) {
»for​ (​int​ i = 0; i < checks.size(); i++) {
»boolean​ shouldAbortTakeoff = commander.isFailing(checks.get(i));
 if​ (shouldAbortTakeoff) {
 return​ Status.ABORT_TAKE_OFF;
  }
  }
 return​ Status.READY_FOR_TAKE_OFF;
  }
 }

There are many ways to iterate over a data structure. The one that beginners are usually taught isn’t exactly the best one.

The code here shows an iteration on a data structure, a List named checks. It uses a for loop and iterates over checks using an index variable i.

This is a very traditional way of iterating, available in all C-style programming languages. It’s often associated with arrays, but in Java, it works with all kinds of indexed collections (but doesn’t work for Set or Map). It has the advantage that you always have the current iteration index, i, at hand.

But in this snippet, we don’t use the index except for accessing the next element of the list. So why should we keep track of it?

What’s more, the index variable opens the door to mistakes. It’s not protected, and you can overwrite it at any time. Getting the termination criterion right is something that beginners notoriously struggle with. This can result in embarrassing IndexOutOfBoundsExceptions.

Most of the time, you don’t really need the level of detail that an index variable gives you. In those cases, you should write loops in a different way, such that the low-level details of the iteration aren’t just protected but are also hidden from the programmer.

This makes your software safer and easier to understand!

Luckily, Java offers several alternative syntaxes for this. As a rule of thumb, you should use the easiest one available.

 class​ LaunchChecklist {
 
  List<String> checks = Arrays.asList(​"Cabin Pressure"​,
 "Communication"​,
 "Engine"​);
 
  Status prepareForTakeoff(Commander commander) {
»for​ (String check : checks) {
»boolean​ shouldAbortTakeoff = commander.isFailing(check);
»if​ (shouldAbortTakeoff) {
 return​ Status.ABORT_TAKE_OFF;
  }
  }
 return​ Status.READY_FOR_TAKE_OFF;
  }
 }

This syntax looks a bit odd first, but proves to be really convenient. Read it as “for each check in checks do the following…” It defines a local variable that we can use to access an item of the collection—String check, in our example—followed by a colon and the data structure that’s iterated upon—checks.

On every iteration, Java makes sure that a new object from the data structure is assigned to check. No need to handle an iteration index anymore! And it even works for arrays and unindexed collections like Set.

In most cases, this is the syntax you should go with. It’s obvious that each element of the collection is processed, and this syntax protects the state of the iteration (the index i from the problem) against manipulation. Note that there’s a naming convention to use for(Type singular : plural) as variable names.

Another alternative looping mechanism is using an iterator like in Avoid Collection Modification During Iteration.

You might ask yourself when it’s more appropriate to use the traditional way of iterating with an index. The answer is: almost never. Most of the time, you just want to process every element of a data structure.

If this is the case, then dealing with indices is an implementation detail you shouldn’t have to worry about. The rare cases where index-based iteration makes sense is when you only iterate over special parts of collections or you explicitly need the index for other purposes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.79.147