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


Objects and Values

Strings and integers have some differences. Integers are “just values”, they can be used in calculations and they can be printed on the screen:

int x = 1;
int y = 2;

y = 3 * x;

System.out.println( "value of y now: " + y );

Strings are a bit “cleverer” and for example know how long they are:

String word1 = "Programming";
String word2 = "Java";

System.out.println( "String "+ word1 +" length: " + word1.length() );

System.out.println( "String "+ word2 +" length: " + word2.length() );

We can determine the length by calling the String method length(). Strings have other methods as well. Integers (or whole numbers, variables of type int) have no methods at all. They do not “know” anything.

Strings are objects, or “something that has methods and a value”. Later we will see many other objects as well.

As we can see in the previous example, an object’s methods are called by adding a dot and a method call after the name of the object:

word1.length()    // String object's name is word1 and its method length() is called
word2.length()    // String object's name is word2 and its method length() is called

The method call is made explicitly to the object. In the above example, we have two objects and first we call the length() method of the String object word1 and then do the same for the object word2.

Our old friend reader is also an object:

Scanner reader = new Scanner(System.in);

Even though readers and strings are both objects, they are not very similar. For example, readers (Scanners) have the nextLine() method, but Strings do not. In the Java programming language, objects must be “born”, in other words created with the new command. Strings are objects that make an exception to this rule! – There are two ways to create a String object:

String banana = new String("Banana");
String carrot = "carrot";

Both of the commands above create a new String object. Using the new command when creating a String objects is uncommon.

The object’s “type” is called a class. The class of a string of characters is called String and the class of readers is called Scanner. Later we learn much more about classes and objects.

ArrayList or an “object container”

Often during programming, we would like to keep many different strings in memory. A very bad idea would be to define a variable for each of them:

String word1;
String word2;
String word3;
// ...
String word10;

This would be such a good-for-nothing solution that it does not almost need an explanation – think of this approach for a word count of 100 or 1000!

Just like other modern programming languages, Java gives us different tools to store many objects neatly in our programs. Now, we take a closer look at ArrayList, which is probably the most used object container in Java.

The following lines of code make use of an ArrayList that holds specifically objects of type String. A couple of strings are stored into the list.

import java.util.ArrayList;

public class ListProgram {

    public static void main(String[] args) {
        ArrayList<String> wordList = new ArrayList<String>();

        wordList.add("First");
        wordList.add("Second");
    }
}

In the above main program method, the first row creates a new ArrayList called wordList, which can be used as a container for String variables. The type of the ArrayList is ArrayList<String>, which means that the ArrayList is meant for storing Strings. The list is created using the command new ArrayList<String>();.

Note: to make the ArrayList work, we must first write an import statement at the beginning of the program either import java.util.ArrayList; or import java.util.*;

When the list is created, two strings are added by calling the list method add. The list will not run out of space, so theoretically the list can contain any amount of Strings (as long as they fit in the computer’s memory).

Internally an ArrayList is – as its name suggests – a list. The added strings automatically go to the end of the ArrayList.

Methods of ArrayLists

ArrayList provides us with many useful methods:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    teachers.add("Anthony");
    teachers.add("Barto");
    teachers.add("Paul");
    teachers.add("John");
    teachers.add("Martin");
    teachers.add("Matt");

    System.out.println("the number of teachers " + teachers.size() );

    System.out.println("first teacher on the list " + teachers.get(0));
    System.out.println("third teacher on the list " + teachers.get(2));

    teachers.remove("Barto");

    if (teachers.contains("Barto")) {
        System.out.println("Barto is on the teachers list");
    } else {
        System.out.println("Barto is not on the teachers list");
    }
}

First a list of strings is created and then 6 names added to it. size tells us the amount of strings in the list. Note: when the method is called, the call should have the following format: teachers.size(). First comes the name of the object, then follows a dot followed by the name of the method.

The strings will be in the list in the order in which they were added to it. By calling the method get(i), we get the value from the index (location) i in the list. The indexing of items in the list starts from 0. This means that the first added string is located at index 0, the second at index 1, and so on.

We can remove strings from lists through the method remove. The method can be used in two ways. First, remove("characters") removes the string given as a parameter. Second, remove(3) removes the 4th String from the list.

At the end of the example, the method contains is called. This method is used for asking the list if it contains the string given as a parameter. If it does, the method returns the value true.

Program output:

Going through an ArrayList

In the following example 4 names are added to the list. Then the whole list is printed:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    teachers.add("Anthony");
    teachers.add("Paul");
    teachers.add("John");
    teachers.add("Martin");

    System.out.println( teachers.get(0) );
    System.out.println( teachers.get(1) );
    System.out.println( teachers.get(2) );
    System.out.println( teachers.get(3) );
}

This solution works, but is really clumsy. What if there were more items in the list? Or less? What if we would not know how many items there are?

First, we create a temporary version:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    teachers.add("Anthony");
    teachers.add("Paul");
    teachers.add("John");
    teachers.add("Martin");
    teachers.add("Matt");

    int place = 0;
    System.out.println( teachers.get(place) );
    place++;
    System.out.println( teachers.get(place) );  // place = 1
    place++;
    System.out.println( teachers.get(place) );  // place = 2
    place++;
    System.out.println( teachers.get(place) );  // place = 3
}

Using our old friend the while command, we can increment the variable place by one until it gets too big:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    teachers.add("Anthony");
    teachers.add("Paul");
    teachers.add("John");
    teachers.add("Martin");
    teachers.add("Matt");

    int place = 0;
    while ( place < teachers.size() ) {  // remember why place <= teachers.size() doesn't work?
        System.out.println( teachers.get(place) );
        place++;
    }
}

Now, printing works regardless of the amount of items in the list.

Using a while loop, and “self indexing” the locations in the list, is usually not the best way to go through a list. A much more recommended way is to use the for-each loop described below.

for-each

Even though the command is usually referred to as for-each, the real name of the command is only for. There are two versions of for, the traditional and the “for-each”. The latter is used now.

Going through items in an ArrayList with for-each is easy:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    teachers.add("Anthony");
    teachers.add("Paul");
    teachers.add("John");
    teachers.add("Martin");
    teachers.add("Matt");

    for (String teacher : teachers) {
        System.out.println( teacher );
    }
}

As we can see, the indexes of the list can be ignored if we go through the content of the list “automatically”.

In the code block of the for command (inside { }) a variable teacher is used. It is defined in the for row, on the left side of the colon. What happens is that every item in the list teachers becomes the value of the variable teacher, one by one. It means that when for is entered, the first teacher is Anthony, the second execution of for makes the teacher become Paul etc.

Even though the for command might seem a bit strange at first, you should definitely get used to use it!

Exercise arraylist-1: Words

Create a program that asks the user to input words until the user types in an empty String. Then the program prints the words the user gave. Try the for repetition sentence here. Use an ArrayList structure in your program. ArrayList is defined like this:

ArrayList<String> words = new ArrayList<String>();
Type a word: ~~Mozart~~
Type a word: ~~Schubert~~
Type a word: ~~Bach~~
Type a word: ~~Sibelius~~
Type a word: ~~Liszt~~
Type a word:
You typed the following words:
Mozart
Schubert
Bach
Sibelius
Liszt

Note: an empty String can be detected this way:

String word = reader.nextLine();

if ( word.isEmpty() ) {  // could also be: word.equals("")
   // word was empty, meaning that the user only pressed enter
}

Exercise arraylist-2: Recurring word

Create a program that asks the user to input words until the user gives the same word twice. Use an ArrayList structure in your program. ArrayList is defined like this:

ArrayList<String> words = new ArrayList<String>();
Type a word: ~~carrot~~
Type a word: ~~celery~~
Type a word: ~~turnip~~
Type a word: ~~rutabaga~~
Type a word: ~~celery~~
You gave the word celery twice

Hint: Remember that ArrayList has the method .contains()

Ordering, reversing and shuffling a list

Items in an ArrayList are easy to order by size. Ordering by size means an alphabetic order when the list items are of type String. Ordering is done as follows:

public static void main(String[] args) {
    ArrayList<String> teachers = new ArrayList<String>();

    // ...

    Collections.sort(teachers);

    for (String teacher : teachers) {
        System.out.println( teacher );
    }
}

We give the list as a parameter for the method Collections.sort. The import line import java.util.Collections; or import java.util.*; needs to be at the beginning of the program in order to get tools of Collections working in our program.

Collections also includes other useful methods:

Exercise arraylist-3: Words in reverse order

Create a program that asks the user to input words, until the user gives an empty string. Then the program prints the words the user gave in reversed order, the last word is printed first etc.

Type a word: ~~Mozart~~
Type a word: ~~Schubert~~
Type a word: ~~Bach~~
Type a word: ~~Sibelius~~
Type a word: ~~Liszt~~
Type a word:
You typed the following words:
Liszt
Sibelius
Bach
Schubert
Mozart

Exercise arraylist-4: Words in alphabetical order

Create a similar program as the previous one, but in which the words are printed in alphabetical order.

Type a word: ~~Mozart~~
Type a word: ~~Schubert~~
Type a word: ~~Bach~~
Type a word: ~~Sibelius~~
Type a word: ~~Liszt~~
Type a word:
You typed the following words:
Bach
Liszt
Mozart
Schubert
Sibelius

ArrayList as a parameter for a method

ArrayList can be given to a method as a parameter:

public static void print(ArrayList<String> list) {
    for (String word : list) {
        System.out.println( word );
    }
}

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    list.add("Java");
    list.add("Python");
    list.add("Ruby");
    list.add("C++");

    print(list);
}

The type of the parameter is defined as an ArrayList of String variables the same way a String ArrayList is defined:

Note that the name of the parameter can be anything:

public static void print(ArrayList<String> printed) {
    for (String word : printed) {
        System.out.println( word );
    }
}

public static void main(String[] args) {
    ArrayList<String> programmingLanguages = new ArrayList<String>();
    programmingLanguages.add("Java");
    programmingLanguages.add("Python");
    programmingLanguages.add("Ruby");
    programmingLanguages.add("C++");

    ArrayList<String> countries = new ArrayList<String>();
    countries.add("Finland");
    countries.add("Sweden");
    countries.add("Norway");

    print(programmingLanguages);    // method is given the list programmingLanguages as a parameter

   print(countries);                 //  method is given the list countries as a parameter
}

The program now includes two lists, programmingLanguages and countries. First the printing method is given the list programmingLanguages. The method print internally refers to the list given as a parameter with the name printed! Next, the printing method is given the list countries. Now, the method uses again the name printed referring to the parameter list.

Exercise arraylist-5: Amount of items in a list

Create the method public static int countItems(ArrayList<String> list) that returns the number of the items in the list. Your method should not print anything. Use a return statement to return the number as shown in the following example:

ArrayList<String> list = new ArrayList<String>();
list.add("Hallo");
list.add("Ciao");
list.add("Hello");
System.out.println("There are this many items in the list:");
System.out.println(countItems(list));
There are this many items in the list:
3

Inside the method, it is possible to influence the items in the parameter list. In the following example, the method removeFirst –as the name suggests– removes the first string from the list. What would happen if the list was empty?

public static void print(ArrayList<String> printed) {
    for (String word : printed) {
        System.out.println( word );
    }
}

public static void removeFirst(ArrayList<String> list) {
    list.remove(0);  // removes the first item (indexed 0)
}

public static void main(String[] args) {
    ArrayList<String> programmingLanguages = new ArrayList<String>();
    programmingLanguages.add("Pascal");
    programmingLanguages.add("Java");
    programmingLanguages.add("Python");
    programmingLanguages.add("Ruby");
    programmingLanguages.add("C++");

    print(programmingLanguages);

    removeFirst(programmingLanguages);

    System.out.println();  // prints an empty line

   print(programmingLanguages);
}

Output:

Pascal
Java
Python
Ruby
C++

Java
Python
Ruby
C++

Similarly a method could, for example, add more strings to the list it received as a parameter.

Exercise arraylist-6: Remove last

Create the method public static void removeLast(ArrayList list), which removes the last item from the list. Example code:

ArrayList<String> brothers = new ArrayList<String>();
brothers.add("Dick");
brothers.add("Henry");
brothers.add("Michael");
brothers.add("Bob");

System.out.println("brothers:");
System.out.println(brothers);

// sorting brothers
brothers.sort();

// removing the last item
removeLast(brothers);

System.out.println(brothers);

Example output:

brothers:
[Dick, Henry, Michael, Bob]
[Bob, Dick, Henry]

As we notice from the example above, an ArrayList can be printed as it is. The print formatting is not usually what is sought after, so we are forced to handle the printing ourself. For example, with the help of the for command.

Numbers in an ArrayList

ArrayLists can be used to store any type of values. If the stored variables are of integer type, there are a couple of details to remember. An integer ArrayList is defined like this: ArrayList<Integer>, instead of writing int you must write Integer.

The method remove does not work like expected when the list consists of int numbers::

public static void main(String[] args) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();

    numbers.add(4);
    numbers.add(8);

 
    // this removes the number 4 from the list
    numbers.remove(Integer.valueOf(4));

    // tries to remove the number from the index 8, does not work as expected!
    numbers.remove(8);

}

numbers.remove(4) tries to remove the item in the index 4 from the list. There are only 2 items in the list, so the command generates an error. We must use a slightly more complicated command if the number 4 needs to be removed: numbers.remove( Integer.valueOf(4) );

ArrayLists can also be used to store doubles (decimal numbers) and characters (char variables). The lists can be defined as follows:

        ArrayList<Double> doubles = new ArrayList<Double>();
        ArrayList<Character> characters = new ArrayList<Character>();

Exercise arraylist-7: Sum of the numbers

Create the method sum, which receives a list of numbers (ArrayList) as a parameter and then calculates the sum of the items in that list.

Create the method using the following program body:

public static int sum(ArrayList<Integer> list) {
    // write your code here
}

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(3);
    list.add(2);
    list.add(7);
    list.add(2);

    System.out.println("The sum: " + sum(list));

    list.add(10);

    System.out.println("the sum: " + sum(list));
}

Program output:

The sum: 14
The sum: 24

Exercise arraylist-8: Average of numbers

Create the method average, which receives a list of numbers (ArrayList<Integer>) as a parameter and then calculates the average of the items in that list.

Note: the method should use the method sum from the previous exercise to calculate the sum of the parameters.

Create the method using the following program body:

public static double average(ArrayList<Integer> list) {
    // write your code here
}

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(3);
    list.add(2);
    list.add(7);
    list.add(2);

    System.out.println("The average is: " + average(list));
}

Program output:

The average is: 3.5

ArrayList as return value of a method

ArrayList can also be returned from a method as a return value. In the next example, a method creates an ArrayList, adds three integers into the list and then returns the list. Pay attention to how the main program assigns the list returned by the method as a value into a variable that has the same type as the return value:

import java.util.*;

public class Main {

    public static ArrayList<Integer> addNumbersToList(int num1, int num2, int num3){
        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(num1);
        list.add(num2);
        list.add(num3);

        return list;
    }

    public static void main(String[] args) {
        ArrayList<Integer> numbers = addNumbersToList(3, 5, 2);

        for (int number : numbers) {
            System.out.println( number );
        }
    }
}

Exercise arraylist-9: The lengths of the Strings

Create the method lengths that gets a list of String variables as a parameter and returns an ArrayList that contains the lengths of the Strings in the same order as the original list.

public static ArrayList<Integer> lengths(ArrayList<String> list) {
    // write your code here
}

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    list.add("Hallo");
    list.add("Moi");
    list.add("Benvenuto!");
    list.add("badger badger badger badger");
    ArrayList<Integer> lengths = lengths(list);

    System.out.println("The lengths of the Strings: " + lengths);
}

Program output:

The lengths of the Strings: [5, 3, 10, 27]

Exercise arraylist-10: The Greatest

Create the method greatest, which receives a list of numbers (ArrayList<Integer>) as a parameter and then returns the greatest number in the list as a return value.

public static int greatest(ArrayList<Integer> list) {
    // write your code here
}

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(3);
    list.add(2);
    list.add(7);
    list.add(2);

    System.out.println("The greatest number is: " + greatest(list));
}

Program output:

The greatest number is: 7

Exercise arraylist-11: Variance

Create the method variance, which receives a list of integers as a parameter and then returns the sample variance of that list. You can check how a sample variance is calculated in Wikipedia, under “Population variance and sample variance”.

Note: the method should use the method average of exercise 64 to calculate the average of the parameters. The method should be called only once!

public static double variance(ArrayList<Integer> list) {
    // write your code here
}

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(3);
    list.add(2);
    list.add(7);
    list.add(2);

    System.out.println("The variance is: " + variance(list));
}

Program output:

The variance is: 5.666667

(The average of the numbers is 3.5, so the sample variance is ((3 - 3.5)² + (2 - 3.5)² + (7 - 3.5)² + (2 - 3.5)²)/(4 - 1) = 5,666667.)

Note while testing your program! Sample variance for a list that contains only one item is not defined! It causes a division by zero in the formula. Java considers the result of division by zero as a Not a Number (NaN).