Flow Control I: Loops and Branches
[Part 3 of 11]


In this part, we'll start to look at flow control - how we order a program's instructions into the sequences we want. Specifically, we'll look at looping structures which allow us to repeat code with slight variations, and branches that allow us to split the path through our code into two or more alternative story-lines. As we'll see, loops also help us manage our arrays.


Further info:

The use of the ++ ("plus plus") increment operator is worth knowing more about, in part because it is actually slightly more complex when used outside of loops, but also because it's an important part of programming culture. There are actually a few such operators in Java:

i++ use, and then increment by one.
i-- use, and then decrement by one.
++i increment by one, and then use.
--i decrement by one, and then use.

As you can see, the full list is quite confusing, not least because people use i++ in loops, when actually they mean ++i. To see the difference, you need another variable:

Starting with i = 1 in both cases:
j = i++ : i is 2, j is 1.
j = ++i : i is 2, j is 2.

Despite the fact that in for-loops the increment is done after each run and before the condition is checked, so we'd ideally like to change the value then use it (++i), in for-loops, i++ is treated as ++i, with i++ being the standard way of writing it. This is because the whole operation is done (i = i + 1) before the condition is checked, rather than as the condition is checked.

You may have heard of a language called "C++". Bjarne Stroustrup, its writer, developed it from a language called "C", so "C++" was "C, incremented", though, ironically, not before use. Bjarne has also suggested that the "++", which was an operator in C, originally might have come from Newspeak's "double-plus".

 


Quiz:

What is "i" at the end of this code?

   int i = 3;
   for ( ; i >= 0; i--) {
      System.out.println("i = " + i);
   }
   System.out.println("i = " + i);

Prints as its last line _____________.

  1. "i = -1"
  2. "i = 0"
  3. "i = 1"
  4. ... nothing, you crazy crazy individual, i is out of scope and the code breaks

Correct! i is in scope, because, rather unusually, we declare it outside of the for-loop. At the end of the i = 0 loop run, i is decremented to -1, and then the condition is checked. i is no longer greater than or equal to zero, so the loop ends. Usually i would be destroyed at this point, but because i is created outside the loop, it still has scope and survives, and the last line prints its -1 value.


Further ideas / info:

The examples of loops given hide another little cultural aside, which is to do with loop counting variables. You may have noticed that we tend to use the letters 'i' and 'j' for loop counters. By convention, a lot of programmers use 'i','j', and 'k' as the names of the first, second, and third loop counters in nested loops. This was originally from mathematics ('i' is for index), but this use, probably together with 'n' being the number in a sample, led to the early 3rd generation language FORTRAN taking variables starting 'i' to 'n' inclusive as being integer variables (others being other data types). 'i', 'j' and 'k' were thus the first three simplest integer variable names, and were therefore most often used for loop counters. Programmers still stick to this convention now, unless dealing with some specific coordinate system - so, for example, when dealing with real space we might use something more obvious, like 'x', 'y', and 'z'.

Note that because the scope of for loops is just the for-loop declaration and loop block, you can have multiple for-loops in the same outer block (for example, the main block) with the same variable name, provided they aren't nested inside another loop using the same variable name. Indeed, it sometimes helps clarify things if loops to do similar jobs always have the same variable names, especially when you are dealing with looping multiple times through the same array. For example, when looping through a 2D array, it helps if you always call the first dimension index 'i' and the second 'j' -- you are much less likely to make mistakes. You can use 'i' and 'j' in multiple looping structures down through a program, provided an 'i' loop isn't inside another 'i' loop, and the same for 'j'.

 


Quiz:
Which is the correct line of Java to get this code printing an array's values out, so that each value in a row is next to the other, but so the code drops a line on the printout at the end of each row, starting each row on a fresh line?

for (int i = 0; i < intArray.length; i++) {
   for (int j = 0; j < intArray[i].length; j++) {
      ________________________________________
   }
   System.out.println("");
}

 

  1. System.out.print(intArray[i][j] + " ");
  2. System.out.print(intArray[j][i] + " ");
  3. System.out.println(intArray[i][j]);
  4. System.out.println(intArray[j][i]);
  5. System.out.println(intArray);

Correct! The println statement drops a line each time it runs, so it can't be that. The print statement (which we haven't seen before) prints things to the screen but doesn't drop a line after it does it, so stuff builds up on the same line. Note we put a space between each number, and when the row increments to the next row, we use println just to drop to a new line in the printout. Printing the array name won't print the array, sadly - it just prints what looks like gibberish, but is actually a reference code used by the JVM. The options with the index order as [j][i] are the wrong way round.


Note, with the "?" ternary operator, you can use it in variable assignment, but also in some other situations. So, for example:

System.out.println(Math.random() < 0.5 ? "ROFL" : "LOL");

(Math.random() gives a random number between 0.0 and just less than 1.0.)

Further info:

In these slides we mention a change in 'Java 7'. This raises two issues: how languages change, and how Java itself is numbered.

All languages change, and programming languages are no different. The key question is whether changes are back compatible, that is, don't break existing code. Most languages evolve by adding new programming ideas; older ways of doing things being marked as deprecated, i.e. just to be avoided (you may occasionally see the Java compiler advising you about this). However, occasionally lanaguage developers take a deep breath and make changes that are not back compatible. Introducing new keywords is an example of this, as people may have used the new term as a variable name. This is one reason you can force the java complier to compile to older versions of the language.

Java has avoided major back-incompatible changes, the largest change being in the way user interaction was processed (between 1 and 1.1) - though a number of keywords have been added over the years.

The Java numbering scheme for different versions of the language has changed over the years, but broadly the scheme went 1, 1.1, 1.2, 1.3, 1.4, 5, 6, 7, with version 8 released in 2014. This is somewhat confused by the fact that the Java Development Kit seems to have kept the old numbering scheme, so many developers refer to the current version as 1.8. You can find out what was added at each stage, and plans for the future, on this Wikipedia page on the versions.


Quiz:

Fill in the correct condition to get the code to print "Meh":

   boolean a = false;
   if (
_______________________) {
      System.out.println("Hello World");
   } else {
      System.out.println("Meh");
   }


  1. !a
  2. a
  3. you've got the funk, shout out

Correct! 'a' is false, so checking whether 'a' is true will result in the 'else' statement running, which is what we want. The shorthand for this is just (a). (!a) is the equivalent of (a == false). Sadly java doesn't care whether you have the funk. We do though, if that's any comfort...

 


[Key ideas from this part]