Home Structuring loops
Single-iteration loops
Never write a loop (for
loop or while
loop) that
will either never run or will always runs exactly once. If a loop never runs, just delete
it. If a loop always runs once, you didn't really need a loop to begin with.
You should never write a loop that look this:
for (int i = 0; i < 0; i++) { System.out.println("foo"); }
Why? The loop will never actually run, so the code can just be completely deleted.
Similarly, never write a loop that looks like this:
for (int i = 0; i < 1; i++) { System.out.println("foo"); }
This loop will only ever run once, so we can get rid of the loop and rewrite the code to look like this:
System.out.println("foo");
Sometimes, it's not necessarily entirely obvious when a loop never runs or runs only once. For example, take the following:
int n = // ... for (int i = 3; i < (n + 1) / n; i++) { System.out.println("foo"); }
In this case, it turns out that the expression (n + 1) / n
can only be
one of three values: 0 when n < 0
, 2 when n == 1
, and
1 when n > 1
. (The code throws a DivideByZeroException
if
n == 0
.)
Since we always start i
at 3, that means that the condition will always
be false. That means that the loop will never run, and we can delete this loop
completely.
These types of edge cases, where it's not obvious how many times a loop will run, are rare, but is still worth watching out for.
Special-casing specific iterations
Likewise, avoid structuring the contents of a loop so that a segment
of it runs only during a specific iteration. For example, avoid adding in an
if
statement into a loop that will always run only during the first
iteration.
In general, you should always try and write loops where their content is "generalized".
That is, avoid adding in if statements
that will run only during specific
iterations of the loop – it's usually an indication that your code could have
been structured more elegantly.
For example, the following code snippet is bad style:
for (int i = 0; i < 10; i++) { System.out.print("-"); if (i == 4) { System.out.print("*"); } }
What this code snippet does is print out a star surrounded by five dashes to either
side: -----*-----
.
The reason why this code snippet is bad style is because the way the loop is structured doesn't really make the "symmetry" of our output very clear. It's also bad because we ended up hard-coding a specific case into our loop. The entire point of a loop is to repeat a certain task a given number of times, and it's inelegant to write a loop that repeats a certain task a set number of times, except in one specific, special case.
A better way of writing the above code snippet would be like so:
for (int i = 0; i < 5; i++) { System.out.print("-"); } System.out.print("*"); for (int i = 0; i < 5; i++) { System.out.print("-"); }
When we look at this improved version, we can immediately see that there's some redundancy. Once we factor that out, we get our final, best version:
drawLine(); System.out.print("*"); drawLine(); // ...snip... public static void drawLine() { for (int i = 0; i < 5; i++) { System.out.print("-"); } }
As another example, avoid writing a loop that does something special on the first or last iteration. In those cases, you're usually able to "shorten" the loop and pull the first or last case outside of the loop, making the intent of your code more clear.
Of course, that isn't to say that it's bad to have if
statements
and such inside of your loops. It's perfectly fine and encouraged to combine if
statements and loops. For example, the following would be perfectly acceptable and ok:
public static void printPrimeNumbers(int start, int end) { for (int i = start; i < end; i++) { if (isPrime(i)) { System.out.print(i + " "); } } } public static boolean isPrime(int number) { // ... }
Because this if
statement could potentially trigger multiple times while
our loop runs + isn't targeted towards a single iteration, this loop would be considered
good style.
All this said, sometimes you may find that having to special-case a certain event in a loop is unavoidable. In these cases, you should think carefully through your code and perhaps consult with a TA, and just accept your code as-is and move forward if you cannot think of a cleaner way of expressing your code.
Break and continue
Do not use break
and continue
statements.
While there's nothing inherently bad with break
or continue
,
newer programmers often have a habit of misusing them as a shortcut or crutch
to avoid writing clean code.
Of course, not all beginners abuse break
or continue
, but
enough do that we've decided to ban them outright in CSE 14x both to ensure that your
code stays clean and to preserve the sanity of the TAs who must grade your assignments.
To be fair, we're also careful to structure all of our assignments and practice problems
so that you never need to use them. If you do find yourself wanting to use
break
or continue
, that is a sign that there is a better way to
do whatever it is you're trying to do.
If you think you've found a situation where you genuinely think using break
or continue
is the right solution, it would be a very good idea to go talk to
Adam or your TA to get confirmation.