Object-Oriented Programming with Java, part I + II

cc

This material is licensed under the Creative Commons BY-NC-SA license, which means that you can use it and distribute it freely so long as you do not erase the names of the original authors. If you make changes in the material and want to distribute this altered version of the material, you have to license it with a similar free license. The use of the material for commercial use is prohibited without a separate agreement.

Authors: Arto Hellas, Matti Luukkainen
Translators to English: Emilia Hjelm, Alex H. Virtanen, Matti Luukkainen, Virpi Sumu, Birunthan Mohanathas, Etiënne Goossens
Extra material added by: Etiënne Goossens, Maurice Snoeren, Johan Talboom
Adapted for Informatica by: Ruud Hermans

The course is maintained by Technische Informatica Breda


About blocks and nested loops

A piece of code that begins with a curly bracket { and ends with a curly bracket } is called a block. As we’ve already seen, blocks are used - among other things - to denote the code of conditional and loop sentences. An important feature of a block is that variables defined within it only exist within it..

In the following example we define the string variable stringDefinedWithinBlock within the block of a conditional sentence, which therefor will only exist within the block. The variable introduced within the block cannot be printed outside of it!

int number = 5;

if( number == 5 ){
    String stringDefinedWithinBlock = "Yeah!";
}

System.out.println(stringDefinedWithinBlock); // does not work!

However, you can use and manipulate variables defined outside of the block in the block.

int number = 5;

if( number == 5 ) {
    number = 6;
}

System.out.println(number); // prints 6

You can have any kind of code within a block. For example, a for loop can have another for loop within it or say, a while loop. Let’s inspect the following program:

for(int i = 0; i < 3; i++) {
   System.out.print(i + ": ");

   for(int j = 0; j < 3; j++) {
      System.out.print(j + " ");
   }

   System.out.println();
}

The program prints the following:

0: 0 1 2
1: 0 1 2
2: 0 1 2

So what happens in the program? If we only think about the outer for loop, its functionality is easy to understand:

for(int i = 0; i < 3; i++) {
   System.out.print(i + ": ");

   // the inner for-loop

   System.out.println();
}

So first i=0 prints 0: and a carriage return. After this i grows and 1 is printed and so forth, so the outer for makes this happen:

0:
1:
2:

The inner for loop is also easy to understand separately. It prints out 0 1 2. When we combine these two, we’ll notice that the inner for loop carries out its print just before the outer for loop’s carriage return.

variables defined outside of a for loop as its condition

Let’s inspect the following alteration to the previous example:

for(int i = 0; i < 3; i++) {
    System.out.print(i + ": ");

    for(int j = 0; j <= i; j++) {
        System.out.print(j + " ");
    }

    System.out.println();
}

The amount of runs the inner for loop does now depends on the value of the variable i of the outer loop. So when i=0 the inner loop prints 0, when i=1 the inner loop prints 0 1. The entire output of the program is as follows:

0: 0
1: 0 1
2: 0 1 2

The following program prints out the multiplication tables of the numbers 1 .. 10.

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

    for(int j = 1; j <= 10; j++) {
        System.out.print(i * j + " ");
    }

    System.out.println();
}

The output looks like this:

1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100

The topmost row has the multiplication table of 1. At the beginning i=1 and the inner loop’s variable j gets the values 1…10. For each i, j value pair their product is printed. So at the beginning i=1, j=1, then i=1, j=2, …, i=1, j=10 next i=2, j=1, and so forth.

Of course the multiplication table program can be cut in to smaller pieces, too. We can define the methods public void printMultiplicationTableRow(int multiplier, int howManyTimes) and public void printMultiplicationTable(int upTo), in this case the structure of our program could be as follows:

public class MultiplicationTable {

    public void print(int upTo) {
        for(int i = 1; i <= upTo; i++) {
            printMultiplicationTableRow(i, upTo);

            System.out.println();
        }
    }

    public void printMultiplicationTableRow(int multiplier, int howManyTimes) {
        for(int i = 1; j <= howManyTimes; i++) {
            System.out.print(i * multiplier + " ");
        }
    }
}

Now calling new MultiplicationTable().print(5); prints the tables below.

1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25

Exercise nesting-1: Array to stars

Implement the method public static printArrayAsStars(int[] array), which prints a line with stars for each number in the array. The line length is determined by the number.

The program skeleton:

public class Main {
    public static void main(String[] args) {
        int[] array = {5, 1, 3, 4, 2};
        printArrayAsStars(array);
    }

    public static void printArrayAsStars(int[] array) {
        // code here
    }
}

The above example should cause the following output:

*****
*
***
****
**

As seen the first line has 5 stars and the reason for that is that is that the first element of the array is 5. The next line has one star since the second element of the array is 1, etc.

Exercise nesting-2: Night sky

Let us implement a program that prints the Night sky. The sky has a star density. If the density is e.g. 0.1, roughly 10% of the sky is covered with stars.

Stars print out as *-characters. Below an example that demonstrates how the NightSky could be used when all the steps of the assignment are done.

NightSky NightSky = new NightSky(0.1, 40, 10);
NightSky.print();
System.out.println("Number of stars: " + NightSky.starsInLastPrint());
System.out.println("");

NightSky = new NightSky(0.2, 15, 6);
NightSky.print();
System.out.println("Number of stars: " + NightSky.starsInLastPrint());
        *     *                  *
    *             * *         *      **
                                     *
        *       *      *         *  *
 *     *                     *
*            * *                   *
*  * *           *          * *  **
                            *  *
          *               *
     *                             *
Number of stars: 36

 * * *     *
     * *   *
*     *
   *  *       *
*       *   * *
* ** **     *
Number of stars: 22

Note! in the assignment use the for-clause. Despite that the previous chapter described nested loops, in this assignment we “hide” the nested loop within a method.

Exercise nesting-2.1: Class NightSky and a star line

Create the class NightSky, that has three object variables: density (double), width (int), and height (int). The class should have 3 constructors:

  • public NightSky(double density) creates a NightSky object with the given star density. Width gets the value 20 and height the value 10.
  • public NightSky(int width, int height) creates a NightSky object with the given width and height. Density gets the value 0.1.
  • public NightSky(double density, int width, int height) creates a NightSky-object with the given density, width and height

Add to the class NightSky the method printLine, that prints one line of starts. The line length is determined by the value of the instance variable width and the instance variable density determines the star probability. For each printed character you should use a Random object to decide if it prints out as a white space or a star. The method nextDouble will probably be of use now.

In the following example:

NightSky NightSky = new NightSky(0.1, 40, 10);
NightSky.printLine();
            *  *                  *

Exercise nesting-2.2: Printing the night sky

Add the class NightSky the method print, that prints the night sky of the given size. Use the method printLine to print each separate line of the night sky. An example in the following:

NightSky NightSky = new NightSky(8, 4);
NightSky.print();
    *

  *
    *

Exercise nesting-2.3: Counting the number of stars

Add the class NightSky an instance variable starsInLastPrint (int) and the method starsInLastPrint(), that returns the number of stars printed in the previous night sky. Example in the below:

NightSky NightSky = new NightSky(8, 4);
NightSky.print();
System.out.println("Number of stars: " + NightSky.starsInLastPrint());
System.out.println("");

NightSky.print();
System.out.println("Number of stars: " + NightSky.starsInLastPrint());
 *

Number of stars: 1

 *
      *
*

Number of stars: 3