Flow Control   
Peter Komisar   
©      Conestoga College                latest version    5.4    2008

'New Topic in JDK 1.5',   Generics   // just for reference
See the following for a short explanation. Supplied for
reference only. Not part of current course material. 
Generics.html


Flow & Control    


Control

A program can be thought of as a list of instructions that
a computer is able to execute in a predictable manner.
At any given instant in the execution of this list of commands,
one instruction is being processed by the CPU, the Central
Processing Unit.

From the program's vantage point, it is the command that
has control of the processor and indirectly the whole PC.
In this sense, the program has 'control' over the processor.

When a program is running, the collective effect of the list
of instructions being processed, one at a time at the CPU
provides a sense that the program has control over the
the activities of the system.

You can think of the CPU as the active component processing
a list of passive instructions, like a buzz saw cutting through
wood. Alternatively, you can picture the CPU as a passive and
obedient robot whose actions are totally controlled by a list of
program instructions. Wherever you put the emphasis, both
descriptions allude to this concept of control.


Flow

Flow implies movement. As each command in a program
is executed in sequence by the central processing unit,
there is a flow of control developed. At the assembly level
one set of instructions might tell the CPU to go to another
memory location and execute the instruction there which in
turn may lead the CPU to execute an instruction stored at
yet another location.

This dynamic sequence of events describes the flow of
control. The flow of control is a description of the order in
which commands are executed. Programming languages
supply different keywords that are used in control
statements to control the flow of execution of commands. 


Control of Flow or Flow Control

Some authors think it is more accurate to name this topic
'Flow of Control'. The topic is also been called 'Flow Control
The latter seems to be easier to say and remember.


Structural Elements & Statements


Primitives

The most elemental parts of a programming language
are the primitive types. The primitives, called prime types,
cannot be broken down any smaller. A char, that stores
the letter 'z' can't be broken down to anything smaller. It
is a prime type. The char can be treated as an operand
and be worked on by Java's operators. A char variable
can be incremented, inverted, compared, assigned or
shifted etc.


Expressions

Groups of operators and the operands that operators
work on, can be joined together in complex associations
called expressions. An expression evaluates to something.
Regardless of how complex the grouping of operators and
operands are they ultimately resolve to a single value, or
a single variable representing some value or a void in the
case of a method expression. In Java anything that evaluates
to a variable, a value or a void is by definition an expression.

Java Expressions Evaluate To:

// In Java an expression evaluates to a variable, a value or a void


An instantiations of a class evaluates to a reference value
that can be stored in a
variable. Sometimes an expression
doesn't resolve to a value, but only to a variable.
You can
think of 2 * x as resolving to the variable 2x. A method can
return specific
values but also can return void. A method
call is also a type of expression. In the
following example
everything supplied as an argument to the println method
is an
expression that ultimately resolves to a String value.

Example  

System.out.println( " The square root of 91 is " + Math.sqrt(91) );
 

Statements

After the expression, the next level of or programmatic
organization is called the statement. Statements are to
a program what sentences are to grammar. While in
grammar, the period ends the sentence, in Java the
semi-colon or curly brace end the statement. When a
Java expression is concluded with a semi-colon or
a
curly brace , the expression becomes a statement.

The Block Statement

A block defined by curly braces is also a statement.
The block statement is also called the 'compound'
statement as it is typically used to enclose multiple
statements.

You can optionally put a semicolon after a block if you
like. You can think of a block as a statement that
has
a semi-colon supplied implicitly. Following is an empty
block with a semi-colon supplied explicitly.

Example     {   } ;    // an empty block statement


The Empty Statement

Even a semicolon by itself is a statement, appropriately
called an empty statement. You can't create a statement
like
this in a normal language like English. A period by
itself is just a typo error. Following is an example of an
empty statement.


Example
    

  ;      

// the semi-colon by itself is an empty statement

An artifact created by the empty statement is you can
put any number of these
outside the scope of the class
without a compiler error occurring. The following
code
shows variations on block and empty statements.
 


Example

class Empty
{

  public static void main(String[] args)
  {     
      ;     
    // an empty statement
      {  }     // a pair of braces is an empty block statement
      {  };    // we can end the block with a semi-colon
  };
};

;    // an empty statement outside a class definition!


The empty statement is useful in conditions where
you don't want any action to be taken.  In the following
example the empty statement is used to do nothing
while the 'else clause is supplied with the compound
statement comprised of curly braces enclosing several
statements.
 

Example                

boolean Rain = true;
      if (Rain)
       ;                   // if rain do nothing
     else{
       getBeachBall( );
       getLotion( );
       go_swim( );    // methods defined else where
       }

Another place where an empty statement can be useful
is in a 'for loop'. The two empty statements in the
following 'for loop' runs forever.


Example
          

for(  ;  ;  )                     

// a 'forever' for loop


Statements are typically grouped inside blocks, the
curly braces used by the classes, constructors and
methods. An empty block when used with a method
creates an empty or stub method.

Using Blocks To Create Sub-Scopes

Sometimes a plain unnamed block is used which allows
the creation of sub-scopes scope where 'same named'
variables can co-exist in the same program without causing
name clashes. This can be handy if you wanted to reuse
a section of code that has complex expressions. Normally,
though if you sought to reuse such code you would put this
code into a method.

Example  

// each n is in it's own scope

{int n=7;
 System.out.println(n);}
{int n=8;
 System.out.println(n);}
{int n=9;
 System.out.println(n);}

This isn't allowed with nested scopes. The following
example doesn't compile.

Example 

 {
  int n=7;
     { int n =11; }      // won't compile
 }


The static initializer

The block can also be used to create a static initializer
that will initialize a section of code when the class is
built. This is normally done to improve performance,
where code is readied at class-load time.

Example

class K{
 final static double K;    // assume there is a list of variables set to a default
   static {           // the static initializer can be used to initialize them at class load time
              K= 1.101;          // notice a final variable can be initialized once but only once
             }
   public static void main(String[] args){
  }
}


Selection Statements


One of the most used aspects of computer programs
is that they provide a means of supplying different
responses to different logical conditions. Java supplies
two devices to make these selections, the 'if else'
statement and the 'switch'.

The simpler of the two is the 'if else' statement which
supplies one of two courses of action for a program to
follow. In it's simplest form it just says ' if something is
true do this'. With it's optional else part supplied, the
mode becomes 'if something is true do this, else do that'.

The other device is the switch which Java inherits
from C. In fact Java's flow control devices are in
general similar to those found in C and C++. Java
doesn't use the 'goto' operator. Java does supply
the 'break' and 'continue' keywords that can be used
to supply some of the 'goto' functionality. The switch
supplies several possible routes for control  to follow
based on a given condition.


The 'if else' Statement

The if else statement has the following general form.

Form if 'if else' Statement

 if ( boolean expression) Statement  opt. [ else Statement ]


In the first case it can be used in code to supply an
action if something is true. We saw earlier an example
where nothing was done on the condition being true. 


Example

if (true) do( );     
// the action may be on the same line as the if( ) statement

// or

if (true)
do( );

Multiple Statement Execution

The statement following the test will execute if the
test resolves to the boolean value true. By default,
only the single statement is executed. If the
programmer wants more than one line of code
executed based on this condition a compound
statement needs to be supplied, enclosed in curly
braces.


Example

  if (true){
     doThis( );  // and
     doThat( );
     }

If something should be executed in the case where the
test resolves to false then the optional else statement
is supplied.

Example

 if (true){
    doThis( );
    doThat( );
    }
  else {
    doSomethingElse( );
    }

'If' statements can be nested to create more complex
decision trees. In this case a new pair of options are
supplied to the a branch in the flow of control.


Example

class K1 {
public static void main(String[] args) {
 if (true){
              doThis( );
              doThat( );
              }
              else if (true){
                                  elseDoThis( );
                                  elseDoThat( );
                                  }
                                  else {
                                           doSomethingElse( );
                                          }
  }
static void doThis( )
     {System.out.println("True: Do This.");};
static void doThat( )
     {System.out.println("True: Do That.");};
static void elseDoThis( )
     {System.out.println("False:True: Do elseDoThis.");};
static void elseDoThat( )
     {System.out.println("False:True: Do ElseDoThat.");};
static void doSomethingElse( )
     {System.out.println("False:False: Do SomethingElse");};
}
 

The switch Statement

Where the 'if statement' supplies one of two alternatives
for the flow of control, a switch statement is designed to
supply multiple options for the execution path to follow.
 
A switch has an argument area in which an expression
is tested that resolves to a byte, char, short or int integral
numeric value. This value is compared to the value that
is associated with each of the different cases that are
supplied in the body of the switch statement.

The 'case' statements each must use the keyword 'break'
to return from the executed statements associated with a
given case. Otherwise the flow of control will continue to
execute into the the following cases. When subsequent
cases are executed as a result of the the 'break' keyword
being omitted, the behavior that results is called 'fallthrough'.
Leaving out the 'break statement' is a very common error
that occurs when using the switch statement.

// omitting 'break' keywords results in 'fallthrough'

A default statement can be supplied to handle the
condition where there is no matching case for the value
in the switch. If there is no default case supplied and
there are no matches, then no statements is executed
in the switch statement. The switch statement has the
following form.

The Form of the 'switch' Statement      

switch ( expression resolving to byte, char, short or int ) {
           case 1:   { /*statements*/ }     break;
           case 2:   { /*statements*/ }     break;
           case n:   { /*statements*/ }     break;
           default:   { /*statements*/ }
           }
  // default executes when there is no matching case


Note it is the value following each 'case' keyword that is
compared to the value supplied as an argument to the
switch


Example
 

class K1
     {

     public static void main(String[] args)
        {

         for(int i=1; i<4;i++)
            {

              switch ( i )
                 {

                           case 1:    {case_1( ); }  
                              break;

                           case 2:    { case_2( ); } 
                              break;

                           case 'n':   {case_n( );  } 
                              break;

                          default:   { case_default( );
                }

          }
       }
   }
static void case_1( ){System.out.println("case 1"); }
static void case_2( ){System.out.println("case 2"); }
static void case_n( ){System.out.println("case N"); }
static void case_default( ){System.out.println("default case"); }
}


OUTPUT

> java K1
case 1
case 2
default case

Imitation of switch behavior using if statements

Following is an example of the behavior of the switch
construct being imitated
using nested 'if else' statements.
We make use of the Math class method random( )
to
assist us in generating a random number. Anytime the
number four is generated, no cases match
and the else
branch that represents the switch default case is
executed.

 

Example

class tif{
public static void main(String[]args){
int x=(int)(Math.random( )*4)+1;
   if(x==1)
   to("One");
   else  if(x==2)
   to("Two");
   else if(x==3)
   to("Three");
   else{to("default"); }
   }
static void to(String s){
  System.out.println(s);
  }
}

 
 More on the 'switch' 

The switch fallthrough feature is error-prone. Peter
Van der Linden reports in his text 'Just Java'
that
the fallthrough feature of the switch is rarely used. 
He did an interesting survey w
here he viewed 320
switches in the Java source code, observing less
than 1% used
the fallthrough feature. 

The implication is the fallthrough behavior might
have been better arranged so that fallthrough was
left out by default
and added optionally rather than
the other way around.

.




Iteration Statements


A program can supply code that repeats a process a
predetermined number of times or indefinitely until some
condition is met. Java supplies the common 'for loop' for
iterating an action a specific number of times. Java also
provides 'while' and 'do' while loops for repeating iterative
processes until some condition is met.

The 'for loop' defines three zones in it's body. One each
for initialiation, testing and incrementation. The first zone
is where starting values are set. The second zone resolves
to a boolean value that is true or false. If true, the loop
continues. The final zone is used to increment the starting
value. Following is the form the for loop takes.


Form of the 'for loop'

for  ( initializationtest condition ;  increment )  

 // a determinate loop

The 'for loop' is also called a 'determinate' loop because
the number of times
it will repeat is predetermined. The
variables used in a for loop can be declared inside or
outside the 'for loop'.

Example       

int i;
for ( i = 0; i< 99; i++)

// or        

for (int i = 0; i< 99; i++)

The initialization and increment zones can contain
compound initialization and increments while the
evaluation or testing zone needs to resolve to a
single boolean value. When zones are compounded,
expressions are separated by commas.


Example    

for (int i = 0, j = 0 ; i < 100; i++ , j +=2 )

// the initiation and increment zones can be compound
// but the test condition resolves to a single boolean value


As mentioned earlier an infinite 'for loop' may be created
by leaving out the expressions
of the for loop. The resulting
for loop is left holding two empty statements.

Example          

for ( ; ; ) 

// in fact just leaving the middle condition empty runs
//  the loop forever.


The next example shows the initialization and increment
zones with more than one comma separated expressions.

int i=0;
int j=0;
for( i=0, j=2;j<100&i<50 ;i++,j++)
System.out.println(i+" "+j);

Inside a for loop, compound declarations can be performed
along with initializations. What is not allowed is a nested
declaration. If a declaration occurs in the for loop, it has to
be the first element in the initialization zone.

Bad Compound for Loops

In the following example, the first for loop definition is fine.
The variable j is not in the initialization zone and z takes
it's type the same way x is declared. In the second case,
it appears to the compiler that k is being declared twice
so this doesn't compile. The third loop also doesn't work
as the type declaration of w is nested and so illegal.  (You
may wish to uncomment each of the 'offending' loops to
get the compiler report on each problem.)


Example  

class forTT{
  public static void main(String[] args){
   int j=9;                            // 1. Good
    for(int x=0, z=1; x<4;x++,j++){
     System.out.println( x + "  " + j);
   }
  /*
 int k=0;  // 2. Not OK. The compiler see's this as a double declaration
   for(int x=0, k=4; x<5;x++,k++){
    System.out.println(x + "  " + k);
   }

  int q;           // 3. Also not good! Can't nest w's  type declaration
    for(q=0, int w=4; q<10;q++,w++){
     System.out.println(q + "  " + w);
        }
  */
      }
     }

Keep in mind there are only three regions in the for loop
two which can be compounded
by comma seperation.
You can't nest a type declaration in the initialization zone.

 

The while loop             // indeterminate loops 

The 'while' and the 'do...while' statement are called
'indeterminate loops' because it is unknown when the
condition will change that results in their termination.
Following
is the form of the while loop. It takes a
boolean expression.


Form of the 'while' Statement

while ( boolean expression ) Statement


While the boolean expression is true the statement is
executed. The loop iterates 0 or more times. If the
expression is false control passes to the first line of
code past the statement. If on first evaluation, the
expression resolves to false the statement is never
executed. In the following example the loop never
stops and is like the infinite for loop.

Example
          
int i =1;
while (true){ System.out.println( i ++) }
 

The do while loop

Sometimes a loop is needed that runs based on a boolean
condition however it needs to be executed at least once.
This is the function provided by the do while loop. The do
while loop has the following form.

Form of the 'do ... while' Statement

do  Statement  while  ( boolean expression )


In the next example the variable ' i  ' will increment an
indefinite number of times if start is true. We see though
that is false. Still the loop will execute at least once, and
will be set to 1.

Example 

  class OneUp{
      public static void main(String[] args){
        boolean start=false;
          int i=0;
            do {
                i=++i;
                System.out.println(i);
                }while(start);
            }
       }

OUTPUT

>java OneUp
1

break & continue

The 'break' and 'continue' keywords offer granular control
over the flow control in loops. The 'continue' keyword
moves the flow of control to the next iteration of a loop.
It is only used in loops. If used within nested loops,a
label can be joined to the 'continue' keyword to indicate
which loop will move to it's next iteration. The next line
shows the form of continue.


Form of 'continue' in Use

continue  opt.  label


The 'break' keyword has a more extreme behavior than
continue. It causes control to break right out of the loop
it is contained in.  If used with a label, the break takes
you to the label and control continues after the end of
the block
of code the label has been joined to. The form
the 'break' keyword takes is shown below.


Form of 'break' in Use

break  opt.  label

The next code example shows how break and continue
work first without and then with labels.


Using 'break' & 'continue' Code Sample

class BC{
  public static void main(String[] s){
    int i;
   for(i=1; i <8; i++){
     if (i==5)
     break;                      // breaks right out of the loop
     System.out.println(i);
     }

//***************************
System.out.println( );   // spacer
//***************************
  int j;
  for (j=1;j<8; j++){
      if(j==5)
     continue;        // continues with the next iteration
     System.out.println(j);
   }

//***************************
System.out.println( );   // spacer
//***************************
         int x;
         int y;

/* In the following compound loop, when the system
 * breaks to label A associated with the break, control

 * continues at the end of the block that the label is
 * associated with, thus  leaving
  the outer loop 
*/

labelA:  for(x=0; x < 3; x++)
    {

     for(y=0; y < 3; y++)
       {

       if(y==1)
         break labelA;
         System.out.println(x + " " + y );
       }
     }  // end of labeled block from where code continues

//***************************
System.out.println( );   // spacer
//***************************
         int z;
         int t;

  labelB: for(z=0; z < 3; z++)
               {

               for(t=0; t < 3; t++)
                 {

                  if(t==1)
                  continue labelB;
                  System.out.println(z + " " + t );
                  }
                } // continues to labeled loop and
                 // proceeds with next iteration

            } 
        }

     Output
 
 1
 2
 3
 4

 1
 2
 3
 4
 6
 7

 0 0 

 0 0 
 1 0
 2 0
.



Other Flow Control Terms

Exceptions deal with the special case of where control
goes when something goes wrong. Exceptions are dealt
with in a very formal and unified way in Java and so are
treated as a separate topic. The keywords 'throw' and
'throws are really flow control elements associated with
exception handling and are covered with exceptions.

The 'goto' keyword is reserved so we don't have to worry
about it. The return keyword is used in methods to return
values but is also used as a means of controlling flow.
The return keyword can be used to exit a method before
it is completed based on some condition.

Example

class Return{
    public static void main(String[]args){
       if (args.length ==0) {
         System.out.println("Enter a number at the command line");
          return;
          }
         System.out.println("Your number is " +args[0]);
          }
      }


Self Test                              Self Test With Answers


1) Which of the following is not a valid statement?

a)    ;
b)   {  }
c)   (  );
d)   {  };
 

2) Which of the following lines needs be commented out in order
    for the following code to compile? Select a, b, c or d.

                      {
/*a*/               int i=3;
/*b*/              {  int i= 7;
/*c*/               i=13;  }
/*d*/              { int i= 11; }
                      }
 

3) A static initializer does not need which of the following.

a) braces
b) a block statement
c) the static keyword
d) an identifier
 

4) In the following if else statements what will the result be?

    if (false)
     System.out.println("A");
       else if (false)
     System.out.println("B");
       else if (true)
     System.out.println("C");
      else
     System.out.println("D");

a) A
b) B
c) C
d) D
 

5) True or False?

while(true){ }   and    for( ; ; ){  }  both do the same thing.
 

6) Which of the following keywords prevents fall through in a switch statement?
    a) switch
    b) case
    c) break
    d) default
 

7)  What will the following switch print out?

    int x =0;
    switch( x ) {
    case 1: System.out.println("1");
    break;
    case 2: System.out.println("2");
    break;
    default: System.out.println("3");
    }

a) 0
b) 1
c) 2
d) 3
 

8) Only one of the following for loops will compile? Which is it?

 a)   for(int a=1; b=4; b<6; b++) { }
 b)   for(int x=0, int y=3; x<5;  x++){ }
 c)   int z;
       for(z=0, int t=4; z<10;z++,t++){  }
 d)   for(int x=0, z=1; x<4;x++, z++){ }
 

9 )  What will the following code output?

         labelA:    for(int x=1; x < 3; x++){
                         for(int y=1; y < 3; y++){
                         if(y != 1)
                         continue  labelA;
                        System.out.println(x + " " + y );
                      }
                   }
a) 1 1

b) 1 1
    2 2

c) 1 1
    2 1

d) 1 1
    2 2
    3 3


Control Exercise


Code Sample

class X9{
      public static void main( String argv[] ) {

      boolean flip;
      if(.5>Math.random())
      flip=true;
      else
      flip=false;

      if (flip)
      System.out.println("\n" + "Heads");
      else
      System.out.println("\n" + "Tails");

System.out.println("\n");

//*********** a switch example **************

int i;
for (i = 4;  i > 0; i--) {
     switch ( i ){
     case 4:
     System.out.println("Ready");
     break;
     case 3:
     System.out.println("On your marks");
     break;
     case 2:
     System.out.println("Get set");
     break;
     case 1:
     System.out.println("Go");
     break;
     default:
     System.out.println("Restart");
     }
      try{
           Thread.sleep(1000);
           }
          catch(InterruptedException io){
          }
      }
   }
}
 

Q1 Modify the above code to do the following. Create a
boolean value, with the identifier 'holiday'. The code should
print out to console, 'Rest' if the condition of the if...else
statement is true and 'Work' if it is false. 

// see example in note

Considering  the switch example in the code above . . .

Q2 What happens (in example 2) if the condition in the for
loop of the switch above is changed to i > -1? Explain what
happens here?

Q3 Comment out the 'break' keywords in the above switch.
What happens?  Why?

Q4 Adapt the above switch code to print out a count down
for a rocket take off. i.e. ten, nine eight ... blastoff!  Make
the thread sleep for 1000 milliseconds between counts.

Q5 Write a for loop that loops 10 times.  Put in a print
statement that prints the index i at each loop. Include
an 'if' statement whose 'else' part causes the 5th iteration's
index not to be printed out. (Printing resumes on the 6th
iteration)

Q6 Copy the loop you created in Q5 and change it so it stops
printing after the  5th iteration.