INTRODUCTION TO PROGRAMMING IN JAVA: REPETITION ("FOR" LOOPS)

NOTE: This set of www pages is not the set of www pages for the curent version of COMP101. The pages are from a previous version that, at the request of students, I have kept on line.


CONTENTS

1. Repetition
1.1. pre-test and post-test loops
2. Loops in Java
3. For loops in Java (example)
4. Using the loop parameter (two examples)
5. Example problem - ASCII code output
5.1. Requirements
5.2. Analysis
5.3. Design
 
5.4. Implementation
5.5. Testing
6. Example problem - Arithmetic progression
6.1. Requirements
6.2. Analysis
6.3. Design
6.4. Implementation
6.5. Testing

The first three examples programmes illustrate fixed count pre-test loops using the "for" construct. The first example problem (ASCII character set) also includes a fixed count pre-test "for" loop. The second example problem (arithmetic progression) makes use of a variable count pre-test loop using a "for" construct.




1. REPETITION

A repetition construct causes a group of one or more program statements to be invoked repeatedly until some end condition is met. The condition comprises a Boolean expression of some form. In this respect repetition constructs have three elements:

  1. Start expression
  2. Test expression
  3. Update expression
 

We can identify two main forms of repetition:

  1. Fixed count loops - repeat a predefine number of times.
  2. Variable count loops (also sometimes referred to as conditional loops) - repeat an unspecified number of times (until some condition is met).

To which we could add recursion (routine calls itself). We will confine the following discussion to fixed and variable count loops and briefly describe recursion at a later date.



1.1. pre-test and post-test loops

In addition both loops can be further classified according to whether they are pre-test or post-test loops. In the case of a pre-test loop the end condition is tested for prior to each repetition, while in the case of a post-test loop the end condition is tested for after each repetition. With respect to Java pre-test fixed and variable count loops are supported as well as post test fixed and variable count loops. Languages such as C and C++ support a similar set of loops, while languages such as Ada only support pre test loops.

 

We can illustrate the distinction between pre-test and post-test loops by considering the flow of control associated with each. In the case of a pre-test loop we test before entering the "repeat" statement, thus if on the first attempt the test fails no repetitions will be made; in the case of a post-test loop the "repeat" statement is called at least once.

We can conceive of flow of control in terms of a floor plan comprising "rooms", "lobbies" and "corridors"; where "rooms" represent program statements, "lobbies" represent choice points, and "corridors" the connections between statements. We can then (in virtual terms) "run" round the floor plan simulating the flow of control. The floor plans given in Figure 1 thus simulate the flow of control that differentiates a pre-test loop from a post-test loop.

Generic activity diagrams for the pre- and post-test loop constructs are presented in Figure 2.

pre-test AND post-test LOOPS

Figure 1: Distinction between pre-test and post-test loops

ACTIVIRT DIAGRANM FOR PRE-TEST LOOP

(a)

 
ACTIVIRT DIAGRANM FOR POST-TEST LOOP

(b)

Figure 2: Generic activity diagrams for pre-test and post-test loops




2. LOOPS IN JAVA

From the above we can therefore identify four basic types of loop:

  1. Fixed count pre-test loops.
  2. Fixed count post-test loops.
  3. Variable count pre-test loops.
  4. Variable count post-test loops.

In Java (in common with languages such as C and C++) things are not so clear cut. Java supports three types of loop construct:

 
  1. For loops --- To define pre-test fixed or variable count loops.
  2. While loops --- To also define pre-test fixed and variable count loops.
  3. Do-while loops --- To define post-test fixed and variable count loops.

Thus we have two mechanisms for constructing variable and fixed count pre-test loops; which to use and when is entirely up to the whim of the programmer!




3. FOR LOOPS IN JAVA

The general form of a for loop in Java is:

for ( < startExpression > ; 
		< testExpression > ; 
		< updatExpression > ) {
        < sequence of statements >
	}

(Note the semi-colons.) This is a very concise (compared to languages such as Pascal and Ada), method of defining a loop (similar to that found in C and C++) that is sometimes criticised because of its lack of easy interpretation (there is always a trade off between conciseness and understandability). The counter-argument to this is that this form of loop definition is much more versatile than that available in (say) Ada. What ever the case, from the above:

Start expression: Introduces one or more loop parameters (also referred to as the control variables or loop counters). These are introduced using an assignment expression which serves to assign a start value to the loop parameter. Where more than one loop parameter is introduced, each must be separated by a comma.
Test expression: Defines the end condition for terminating the loop. Usually this a simple comparison expression. There can be more than one test expression in which case they must again be separated by commas.
 
Update expression: To avoid infinite repetition the loop parameter(s) must be updated on each repetition. This is usually done using an arithmetic expression. The most straight forward approach being to simply increment the loop parameter by one on each repetition. Again where there is more than one update expression they must be separated by commas.

Note: loop parameters are usually of some scalar numeric type. It is good practice to use parameters of type int or long. This is because real numbers have machine dependent precision associated with them, which may result in loops behaving in an unexpected manner as a result of inexact comparison of the loop parameter with some end condition.

In Table 1 a trivial Java program is presented, incorporating a loop, which outputs a sequence of 10 "smiley faces":

(-:     (-:     (-:     (-:     (-:     
(-:     (-:     (-:     (-:     (-:

Note that the start and end values for the loop are defined as constants and not as magic numbers. This is for sound software engineering reasons because the use of a name conveys much more meaning to a reader than a number.

// SMILEY FACE APPLICATION CLASS
// Frans Coenen
// Tuesday 13 April 1999
// The University of Liverpool, UK
   
class SmileyFace {
 
    // ------------------ METHODS -----------------------
    
    /* Main method  */

    public static void main(String[] args) {	
        int       loopParameter;
	final int START_CONDITION = 0;
	final int END_CONDITION   = 10;
	
	// For loop	
	for (loopParameter = START_CONDITION;loopParameter < END_CONDITION;
							loopParameter++) 
		System.out.print("(-:\t");
	
	// End	
	System.out.println("\n");
	}
    }

Table 1: Java for loop example

In the example the loop parameter is declared before the loop construct and assigned to within the construct. We could have initialised the loop parameter entirely within the loop construct as follows:

for (int loopParameter = START_CONDITION;loopParameter < END_CONDITION;
							loopParameter++)



4. USING THE LOOP PARAMETER

In the example given in Table 1 the loop parameter serves no other purpose than to control the loop. In addition we can make use of the parameter as (say) part of an output statement, or as part of some simple arithmetic. Table 2 gives an example of the first, and Table 3 an example of the second. The code in Table 2 is used to simply output a sequence of numbers (the loop parameter):

0 1 2 3 4 5 6 7 8 9 

The code in Table 3 performs some arithmetic on the loop parameter so that a sequence of even numbers is produced:

0 2 4 6 8 10 12 14 16 18 
// SEQUENCE NUMBERS CLASS
// Frans Coenen
// Tuesday 13 April 1999
// The University of Liverpool, UK
   
class SequenceNumbers { 

    // -------------- METHODS -------------------
    
    /* Main method  */

    public static void main(String[] args) {
	final int START_CONDITION = 0;
	final int END_CONDITION   = 10;
	
	// For loop	
	for (int loopParam = START_CONDITION;loopParam < END_CONDITION;
						loopParam++) 
	    System.out.print(loopParam + " ");
	
	// End	
	System.out.println("\n");
	}
    }

Table 2 Sequence of numbers

// SEQUENCE EVEN NUMBERS CLASS
// Frans Coenen
// Tuesday 13 April 1999
// The University of Liverpool, UK
   
class SequenceEvenNumbers { 

    // -------------- METHODS -------------------
    
    /* Main method  */

    public static void main(String[] args) {
	final int START_CONDITION = 0;
	final int END_CONDITION   = 10;
	
	// For loop	
	for (int loopParam = START_CONDITION;loopParam < END_CONDITION;
							loopParam++) 
	    System.out.print(loopParam*2 + " ");
	
	// End	
	System.out.println("\n");
	}
    }

Table 3 Sequence of even numbers

The same result as that produced by the code in Table 3 can be achieved by rewriting the method as follows:

public static void main(String[] args) {
    final int START_CONDITION = 0;
    final int END_CONDITION   = 19;
	
    // For loop	
    for (int loopParam = START_CONDITION;loopParam < END_CONDITION;
		                             loopParam = loopParam+2) 
	System.out.print(loopParam + " ");
	    
    // End	
    System.out.println("\n");
    }


5. EXAMPLE PROBLEM - ASCII CODE OUTPUT (Fixed count pre-test "for" loop example)


5.1 Requirements

Produce a program that outputs the ASCII character set from 0 to 127.


5.2 Analysis

A class diagram for the proposed solution is given in Figure 3.


5.3 Design

ASCII CHARACTER CLASS DIAGRAM

Figure 3: ASCII character application class diagram

From Figure 3 it can be seen that we require only one class, which we will call AsciiCharSetApp.

5.3.1 AsciiCharSetApp Class


Method Summary
public static void main(String[] args)
           Main (and only) method for resolution of problem. Takes no input but simply contains a for loop to loop through the Unicodes from 0 to 127 inclusive. On each iteration the Unicode and the character equivalent are output.

A Nassi-shneiderman chart for the main method is given in Figure 4. Note the way that the pre-test loop construct is incorporated into the chart. Note also that the counter data item is nothing to do with the loop but will be used to output a carriage return on every sixth iteration of the loop. This is so that the output will be "arranged" in seven columns. The associated activity diagram indicating the flow of control through the program is presented in Figure 5.

NASSI-SHNEIDERMAN CHART FOR ASCII CHARACTER SET APPLICATION CLASS

Figure 4: Nassi-Shneiderman charts for AsciiCharSetApp class main method

FLOW CHART FOR ASCII CHARACTER SET APPLICATION

Figure 5: Activity diagram for ASCII character set application


5.4 Implementation


5.4.1 AsciiCharSetApp Class

// ASCII CHARACTER SET APPLICATION
// Frans Coenen
// Tuesday 12 March 1999
// The University of Liverpool, UK

class AsciiCharSetApp {

    // ------------------ METHODS ------------------------

    public static void main(String[] args) {
        final int START_CONDITION = 0;
	final int END_CONDITION   = 128;
	int counter               = 0;
	
        // Loop	
	for(int loopParameter=START_CONDITION; loopParameter < END_CONDITION; 
						loopParameter++) {
	    System.out.print(loopParameter + " = " + 
	    				(char) loopParameter + " ");
	    if (counter == 6) {
	    	System.out.print("\n");
		counter = 0;
		}
	    else counter++;	
	    }
	    
	// End	
	System.out.print("\n\n");   
	}
    }                 

Table 4: ASCII character set application class

Notes:

  1. Here we have an example of a fixed count ("for") loop.
  2. It is considered good programming practice to define the start and end values for the loop parameters as constants rather than "magic numbers".
  3. The loop parameter is incremented by 1 using the ++ postfix unary operator.
  4. We have used a cast to translate Unicodes (i.e loop parameter settings) to characters.

5.5 Testing

When a program does not include any input testing can be limited to a single invocation of the program. This is because without any input there is no possibility of the outcome of the program being externally influenced in any way. The results form this test run are given in Table 5. Note that some of the character codes given in Table 5 are unprintable. Note also that:

9=Horizontal tab
10=Line feed/carriage return
27=Escape
32=Space
127=Delete
0 =  1 =  2 =  3 =  4 =  5 =  ^[[?1;2c6 =
7 =  8 = 9 =     10 =
 11 =
       12 =
             13 =
14 =  15 =  16 =  17 =  18 =  19 =  20 =
21 =  22 =  23 =  24 =  25 =  26 =  27 =
28 =  29 =  30 =  31 =  32 =   33 = ! 34 = "
35 = # 36 = $ 37 = % 38 = & 39 = ' 40 = ( 41 = )
42 = * 43 = + 44 = , 45 = - 46 = . 47 = / 48 = 0
49 = 1 50 = 2 51 = 3 52 = 4 53 = 5 54 = 6 55 = 7
56 = 8 57 = 9 58 = : 59 = ; 60 = < 61 = = 62 = >
63 = ? 64 = @ 65 = A 66 = B 67 = C 68 = D 69 = E
70 = F 71 = G 72 = H 73 = I 74 = J 75 = K 76 = L
77 = M 78 = N 79 = O 80 = P 81 = Q 82 = R 83 = S
84 = T 85 = U 86 = V 87 = W 88 = X 89 = Y 90 = Z
91 = [ 92 = \ 93 = ] 94 = ^ 95 = _ 96 = ` 97 = a
98 = b 99 = c 100 = d 101 = e 102 = f 103 = g 104 = h
105 = i 106 = j 107 = k 108 = l 109 = m 110 = n 111 = o
112 = p 113 = q 114 = r 115 = s 116 = t 117 = u 118 = v
119 = w 120 = x 121 = y 122 = z 123 = { 124 = | 125 = }
126 = ~ 127 =       

Table 5: Output from ASCII character set application program



6. EXAMPLE PROBLEM - ARITHMETIC PROGRESSION (Variable count pre-test "for" loop example)


6.1 Requirements

Design and implement a Java program that outputs the first N terms of an a.p. (arithmetic progression) of the form:

A, A+D, A+2D, A+3D ...

where A is the first term and D is the common difference.


6.2 Analysis

A class diagram for the proposed solution is given in Figure 6. Note that a total of three classes are proposed. A general class Progression, a sub class of this class called ArithmeticProg, and an application class --- ArithmeticProgApp.

ASCII CHARACTER CLASS DIAGRAM

Figure 6: Arithmetic progression application class diagram


6.3 Design


6.3.1 Progression Class


Field Summary
protected int numberOfTerms
           An instance variable to store the number of required terms in the progression.
protected int firstTerm
           An instance variable to store the required "first term" for the progression.

Constructor Summary
Progression(int numTerms, int fTerm)
           Constructs an instance of the class Progression given a number of terms and a start term.

A Nassi-Shneiderman chart for the above is given in Figure 7.

6.3.2 ArithmeticProg Class

 
NASSI-SHNEIDERMAN CHART FOR PROGRESSION CLASS

Figure 7: Nassi-Shneiderman charts for Progression class constructor

Field Summary
private int commonDifference
           An instance variable to store the "common difference" for the required arithmetic progression.

Constructor Summary
ArithmeticProg(int numTerms, int fTerm, int comDiff)
           Constructs an instance of the class ArithmeticProg, a sub-class of the class progression (see Figure 6), given a common difference. Note that the constructor will also access the super class constructor through the use of the super keyword.

Method Summary
public boolean outputTerms()
           Method to output a sequence of terms comprising an arithmetic progression.

A set of Nassi-Shneiderman charts for the above methods is presented in Figure 8.

NASSI-SHNEIDERMAN CHART FOR ARITHMETIC PROGRESSION CLASS

Figure 8: Nassi-Shneiderman charts for ArithmeticProg class methods


6.3.3 ArithmeticProgApp Class

Field Summary
private static Scanner input
           A class instance to facilitate input from the input stream.

Method Summary
public static void main(String[] args)
           Main (and only) method in the ArithmeticProgApp class. Allows input of data, creation of an ArithmeticProg object, and then invokes the outputTerms ArithmeticProg method to produce an arithmetic progression with the parameters supplied by the user.

A Nassi-Shneiderman chart for the above is presented in Figure 9.


6.4 Implementation


6.4.1 Progression Class (and ArithmeticProg sub-class)

NASSI-SHNEIDERMAN CHART FOR ARITHMETIC PROGRESSION 
	APPLICATION CLASS

Figure 9: Nassi-Shneiderman charts for ArithmeticProgApp class method

// PROGRESSION
// Frans Coenen
// Sunday 26 March 1999
// The University of Liverpool, UK

/********************************************/
/*                                          */
/*               PROGRESSION                */
/*                                          */
/********************************************/

class Progression {

    // ------------------ FIELDS ----------------------

    protected int numberOfTerms;
    protected int firstTerm;

    // ----------------- CONSTRUCTORS -----------------

    /* Progression constructor */

    public Progression(int numTerms, int fTerm) {
         numberOfTerms = numTerms;
         firstTerm     = fTerm;
        }
    }

/********************************************/
/*                                           */
/*         ARITHMETIC PROGRESSION            */
/*                                           */
/********************************************/ 

class ArithmeticProg extends Progression {

    // ------------------- FIELDS ----------------------

    private int commonDifference;

    // ----------------- CONSTRUCTORS -----------------

    /* Arithmetic progression constructor */

    public ArithmeticProg(int numTerms, int fTerm, int comDiff) {
        super(numTerms,fTerm);
        commonDifference = comDiff;
        }

    // ----------------- METHODS -----------------

    /* Output terms method */

    public void outputTerms() {
	final int START_CONDITION = 0;

	// Loop
        for(int loopParameter = START_CONDITION;
		    loopParameter < numberOfTerms;loopParameter++)
            System.out.print(firstTerm + commonDifference*
	    					loopParameter + " ");
        
	// End
	System.out.print("\n\n");
        }
    }                    

Table 6: Progression and arithmetic progression classes


6.4.2 ArithmeticProgApp class

// ARITHMETIC PROGRESSION APPLICATION
// Frans Coenen
// Sunday 26 March 1999
// Revised: Thursday 28 August 2005
// The University of Liverpool, UK

import java.util.*;

class ArithmeticProgApp {

    // ------------------  FIELDS -------------------------

    public static Scanner input = new Scanner(System.in);
    
    // ------------------ METHODS ------------------------

    public static void main(String[] args) {
	// Input
	System.out.println("Input number of terms, first term and");
	System.out.println("common difference (integers): ");
	int newNumTerms  = input.nextInt();
	int newFirstTerm = input.nextInt();
	int newCommDiff  = input.nextInt();
	
        // Create instance of type ArithmeticProg 	
	ArithmeticProg newArithProg = new ArithmeticProg(newNumTerms,
				           newFirstTerm,newCommDiff);

   	// Progression
	newArithProg.outputTerms();
	}
    }                    

Table 7: Arithmetic progression application classes


6.4. Testing


6.4.1. Black box testing

Arithmetic Testing: We should test inputs with negative, zero and positive sample values. A suitable set of test cases is given below. Note that a zero or negative input for "number of terms" will result in no output because the loop is never exercised. Note also that with this many test cases a test harness program seems like a good idea. Some suitable code is presented in Table 8.

TEST CASERESULT
NUMBER OF TERMSFIRST TERM COMMON DIFFERENCEOUTPUT
4 3 23 5 7 9
4 3 03 3 3 3
4 3-23 1 -1 -3
4 0 20 2 4 6
4 0 00 0 0 0
4 0-20 -2 -4 -6
4-3 2-3 -1 1 3
4-3 0-3 -3 -3 -3
4-3-2-3 -5 -7 -9
0 3 2None
-4 3 2None

// ARIHMETIC PROGRESSION TEST APPLICATION
// Frans Coenen
// Tuesday 30 March 1999
// Revised: Thursday 28 August 2005
// The University of Liverpool, UK   

class ArithProgTestApp {

    // ------------------ METHODS ------------------------  
    
    /* Main method */
    
    public static void main(String[] args) {
    	testArithProg1(4);
	testArithProg1(0);
	testArithProg1(-4);
	
	// Loop testing
	
	testArithProg3(0,3,2);
	testArithProg3(1,3,2);
	testArithProg3(2,3,2);
	testArithProg3(10,3,2);
	}
	
    /* Test ArithProg 1 */
    
    public static void testArithProg1(int numTerms) {
    	testArithProg2(numTerms,3);
	testArithProg2(numTerms,0);
	testArithProg2(numTerms,-3);
	}
    
    /* Test ArithProg 2 */
    
    public static void testArithProg2(int numTerms, int firstTerm) {
    	testArithProg3(numTerms,firstTerm,2);
	testArithProg3(numTerms,firstTerm,0);
	testArithProg3(numTerms,firstTerm,-2);
	}
	
    /* Test ArithProg 3 */
    
    public static void testArithProg3(int numTerms, int firstTerm, 
    							   int commDiff) {
	// Create instance of type ArithmeticProg 
	ArithmeticProg newArithProg = new ArithmeticProg(numTerms,
						      firstTerm,commDiff);

   	// Progression
	System.out.println("numTerms: " + numTerms + 
				" firstTerm: " + firstTerm + 
				" commonDifference: " + commDiff);
	newArithProg.outputTerms();
	}

    }

Table 8: Test harness code for arithmetic progression application program


6.4.2. White box testing

Loop testing: Where the user controls the number of repetitions in a variable count loop the loop should be tested (in theory) as follows:

  1. No passes through loop (i.e. skip through loop) --- start value-1.
  2. Only one pass through the loop --- start value.
  3. Two passes through the loop --- start value + 1.
  4. M passes through the loop where M < END_VALUE-1.
  5. END_VALUE-1, END_VALUE, END_VALUE+1 passes through the loop.

The nature of our implementation is such that we do not have a particular end value in mind and thus we cannot define tests related to this, however, the set of tests given in the table below are appropriate in this case.

TEST CASERESULT
NUMBER_ OF_ TERMSFIRST_ TERM COMMON_ DIFFERENCEOUTPUT
0 (start value -1: no passes) 32none
1 (start value: one pass) 323
2 (start value +1: two passes)323 5
10 (somewhere in the middle!) 323 5 7 9 11 13 15 17 19 21

Just for interest the output for 100 terms with a start value of -40 and a common difference of 3 is presented in Table 9.

$ java ArithmeticProgApp
Input number of terms, first term and
common difference (integers):
100
-40
3
-40 -37 -34 -31 -28 -25 -22 -19 -16 -13 -10 -7 -4 -1 2 5 8 
11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59 62 65 68 
71 74 77 80 83 86 89 92 95 98 101 104 107 110 113 116 119 
122 125 128 131 134 137 140 143 146 149 152 155 158 161 164 
167 170 173 176 179 182 185 188 191 194 197 200 203 206 209 
212 215 218 221 224 227 230 233 236 239 242 245 248 251 254 
257   
        

Table 9: Example output from arithmetic progression application program




Created and maintained by Frans Coenen. Last updated 10 February 2015