This site is from a past semester! The current version will be here when the new semester starts.

Week 6 [Mon, Feb 13th] - Topics

Detailed Table of Contents



Guidance for the item(s) below:

As usual, we cover a few more Java topics that are relevant to the iP this week. We start with topics related to data structures that you can use to work with collections of objects, as you'll need to be able to manage a collection of task objects in your iP.

But first, let's learn a programming technique called generics (similar to C++ templates) often used in such data structures.

[W6.1] Java: Generics

Video

W6.1a

C++ to Java → Generics → What are Generics?

Can explain Java Generics

Given below is an extract from the -- Java Tutorial, with some adaptations.

You can use polymorphism to write code that can work with multiple types, but that approach has some shortcomings.

Consider the following Box class. It can be used only for storing Integer objects.

public class BoxForIntegers {
    private Integer x;

    public void set(Integer x) {
        this.x = x;
    }
    public Integer get() {
        return x;
    }
}

To store String objects, another similar class is needed, resulting in the duplication of the entire class. As you can see, if you need to store many different types of objects, you could end up writing many similar classes.

public class BoxForString {
    private String x;

    public void set(String x) {
        this.x = x;
    }
    public String get() {
        return x;
    }
}

One solution for this problem is to use polymorphism i.e., write the Box class to store Object objects.

public class Box {
    private Object x;

    public void set(Object x) {
        this.x = x;
    }
    public Object get() {
        return x;
    }
}

The problem with this solution is, since its methods accept or return an Object, you are free to pass in whatever you want, provided that it is not one of the primitive types. There is no way to verify, at compile time, how the class is used. One part of the code may place an Integer in the box and expect to get Integers out of it, while another part of the code may mistakenly pass in a String, resulting in a runtime error.

Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar , type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.

A generic Box class allows you to define what type of elements will be put in the Box. For example, you can instantiate a Box object to keep Integer elements so that any attempt to put a non-Integer object in that Box object will result in a compile error.


W6.1b

C++ to Java → Generics → How to use Generics

Can use Java Generics

This section includes extract from the -- Java Tutorial, with some adaptations.

The definition of a generic class includes a type parameter section, delimited by angle brackets (<>). It specifies the type parameters (also called type variables) T1, T2, ..., and Tn. A generic class is defined with the following format:

class name<T1, T2, ..., Tn> { /* ... */ }

Here is a generic Box class. The class declaration Box<T> introduces the type variable, T, which is also used inside the class to refer to the same type.

Using Object as the type:

public class Box {
    private Object x;

    public void set(Object x) {
        this.x = x;
    }

    public Object get() {
        return x;
    }
}

A generic Box using type parameter T:

public class Box<T> {
    private T x;

    public void set(T x) {
        this.x = x;
    }

    public T get() {
        return x;
    }
}

As you can see, all occurrences of Object are replaced by T.

To reference the generic Box class from within your code, you must perform a generic type invocation, which replaces T with some concrete value, such as Integer. It is similar to an ordinary method invocation, but instead of passing an argument to a method, you are passing a type argument enclosed within angle brackets — e.g., <Integer> or <String, Integer> — to the generic class itself. Note that in some cases you can omit the type parameter i.e., <> if the type parameter can be inferred from the context.

Using the generic Box class to store Integer objects:

Box<Integer> integerBox;
integerBox = new Box<>(); // type parameter omitted as it can be inferred
integerBox.set(Integer.valueOf(4));
Integer i = integerBox.get(); // returns an Integer
  • Box<Integer> integerBox; simply declares that integerBox will hold a reference to a "Box of Integer", which is how Box<Integer> is read.
  • integerBox = new Box<>(); instantiates a Box<Integer> class. Note the <> (an empty pair of angle brackets, also called the diamond operator) between the class name and the parenthesis.

The compiler is able to check for type errors when using generic code.

The code below will fail because it creates a Box<String> and then tries to pass Double objects into it.

Box<String> stringBox = new Box<>();
stringBox.set(Double.valueOf(5.0)); //compile error!

A generic class can have multiple type parameters.

The generic OrderedPair class, which implements the generic Pair interface:

public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey()	{ return key; }
    public V getValue() { return value; }
}

The following statements create two instantiations of the OrderedPair class:

Pair<String, Integer> p1 = new OrderedPair<>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<>("hello", "world");

The code, new OrderedPair<String, Integer>, instantiates K as a String and V as an Integer. Therefore, the parameter types of OrderedPair's constructor are String and Integer, respectively.

A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.

By convention, type parameter names are single, uppercase letters. The most commonly used type parameter names are:

  • E - Element (used extensively by the Java Collections Framework)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S, U, V etc. - 2nd, 3rd, 4th types


Guidance for the item(s) below:

Next, we learn about some built-in data structures that can be used to manage a collection of objects.

[W6.2] Java: Collections

Video

W6.2a

C++ to Java → Collections → The collections framework

Can explain the Collections framework

This section uses extracts from the -- Java Tutorial, with some adaptations.

A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data.

Typically, collections represent data items that form a natural group, such as a poker hand (a collection of cards), a mail folder (a collection of letters), or a telephone directory (a mapping of names to phone numbers).

The collections framework is a unified architecture for representing and manipulating collections. It contains the following:

  • Interfaces: These are abstract data types that represent collections. Interfaces allow collections to be manipulated independently of the details of their representation.
    Example: the List<E> interface can be used to manipulate list-like collections which may be implemented in different ways such as ArrayList<E> or LinkedList<E>.

  • Implementations: These are the concrete implementations of the collection interfaces. In essence, they are reusable data structures.
    Example: the ArrayList<E> class implements the List<E> interface while the HashMap<K, V> class implements the Map<K, V> interface.

  • Algorithms: These are the methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. The algorithms are said to be polymorphic: that is, the same method can be used on many different implementations of the appropriate collection interface.
    Example: the sort(List<E>) method can sort a collection that implements the List<E> interface.

A well-known example of collections frameworks is the C++ Standard Template Library (STL). Although both are collections frameworks and the syntax look similar, note that there are important philosophical and implementation differences between the two.

The following list describes the core collection interfaces:

  • Collection — the root of the collection hierarchy. A collection represents a group of objects known as its elements. The Collection interface is the least common denominator that all collections implement and is used to pass collections around and to manipulate them when maximum generality is desired. Some types of collections allow duplicate elements, and others do not. Some are ordered and others are unordered. The Java platform doesn't provide any direct implementations of this interface but provides implementations of more specific subinterfaces, such as Set and List. Also see the Collection API.

  • Set — a collection that cannot contain duplicate elements. This interface models the mathematical set abstraction and is used to represent sets, such as the cards comprising a poker hand, the courses making up a student's schedule, or the processes running on a machine. Also see the Set API.

  • List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements. The user of a List generally has precise control over where in the list each element is inserted and can access elements by their integer index (position). Also see the List API.

  • Queue — a collection used to hold multiple elements prior to processing. Besides basic Collection operations, a Queue provides additional insertion, extraction, and inspection operations. Also see the Queue API.

  • Map — an object that maps keys to values. A Map cannot contain duplicate keys; each key can map to at most one value. Also see the Map API.

  • Others: Deque, SortedSet, SortedMap


W6.2b

C++ to Java → Collections → The ArrayList class

Can use the ArrayList class

The ArrayList class is a resizable-array implementation of the List interface. Unlike a normal array, an ArrayList can grow in size as you add more items to it. The example below illustrates some of the useful methods of the ArrayList class using an ArrayList of String objects.

import java.util.ArrayList;

public class ArrayListDemo {

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

        System.out.println("Before adding any items:" + items);

        items.add("Apple");
        items.add("Box");
        items.add("Cup");
        items.add("Dart");
        print("After adding four items: " + items);

        items.remove("Box"); // remove item "Box"
        print("After removing Box: " + items);

        items.add(1, "Banana"); // add "Banana" at index 1
        print("After adding Banana: " + items);

        items.add("Egg"); // add "Egg", will be added to the end
        items.add("Cup"); // add another "Cup"
        print("After adding Egg: " + items);

        print("Number of items: " + items.size());

        print("Index of Cup: " + items.indexOf("Cup"));
        print("Index of Zebra: " + items.indexOf("Zebra"));

        print("Item at index 3 is: " + items.get(2));

        print("Do we have a Box?: " + items.contains("Box"));
        print("Do we have an Apple?: " + items.contains("Apple"));

        items.clear();
        print("After clearing: " + items);
    }

    private static void print(String text) {
        System.out.println(text);
    }
}

Before adding any items:[]
After adding four items: [Apple, Box, Cup, Dart]
After removing Box: [Apple, Cup, Dart]
After adding Banana: [Apple, Banana, Cup, Dart]
After adding Egg: [Apple, Banana, Cup, Dart, Egg, Cup]
Number of items: 6
Index of Cup: 2
Index of Zebra: -1
Item at index 3 is: Cup
Do we have a Box?: false
Do we have an Apple?: true
After clearing: []

[Try the above code on Repl.it]

Resources


[Key Exercise] Numbers list

Add the missing methods to the class given below so that it produces the output given.

Use an ArrayList to store the numbers.

public class Main {

    //TODO: add your methods here

    public static void main(String[] args) {
        System.out.println("Adding numbers to the list");
        addNumber(3);
        addNumber(8);
        addNumber(24);
        System.out.println("The total is: " + getTotal());
        System.out.println("8 in the list : " + isFound(8) );
        System.out.println("5 in the list : " + isFound(5) );
        removeNumber(8);
        System.out.println("The total is: " + getTotal());
    }

}

Adding numbers to the list
[3]
[3, 8]
[3, 8, 24]
The total is: 35
8 in the list : true
5 in the list : false
[3, 24]
The total is: 27

Hint




W6.2c

C++ to Java → Collections → The HashMap class

Can use the HashMap class

HashMap is an implementation of the Map interface. It allows you to store a collection of key-value pairs. The example below illustrates how to use a HashMap<String, Point> to maintain a list of coordinates and their identifiers e.g., the identifier x1 is used to identify the point 0,0 where x1 is the key and 0,0 is the value.

import java.awt.Point;
import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<String, Point> points = new HashMap<>();

        // put the key-value pairs in the HashMap
        points.put("x1", new Point(0, 0));
        points.put("x2", new Point(0, 5));
        points.put("x3", new Point(5, 5));
        points.put("x4", new Point(5, 0));

        // retrieve a value for a key using the get method
        print("Coordinates of x1: " + pointAsString(points.get("x1")));

        // check if a key or a value exists
        print("Key x1 exists? " + points.containsKey("x1"));
        print("Key x1 exists? " + points.containsKey("y1"));
        print("Value (0,0) exists? " + points.containsValue(new Point(0, 0)));
        print("Value (1,2) exists? " + points.containsValue(new Point(1, 2)));

        // update the value of a key to a new value
        points.put("x1", new Point(-1,-1));

        // iterate over the entries
        for (Map.Entry<String, Point> entry : points.entrySet()) {
            print(entry.getKey() + " = " + pointAsString(entry.getValue()));
        }

        print("Number of keys: " + points.size());
        points.clear();
        print("Number of keys after clearing: " + points.size());

    }

    public static String pointAsString(Point p) {
        return "[" + p.x + "," + p.y + "]";
    }

    public static void print(String s) {
        System.out.println(s);
    }
}

Coordinates of x1: [0,0]
Key x1 exists? true
Key x1 exists? false
Value (0,0) exists? true
Value (1,2) exists? false
x1 = [-1,-1]
x2 = [0,5]
x3 = [5,5]
x4 = [5,0]
Number of keys: 4
Number of keys after clearing: 0

[Try the above code on Repl.it]

[Key Exercise] weekly roster

The class given below keeps track of how many people signup to attend an event on each day of the week. Add the missing methods so that it produces the output given.

Use an HashMap to store the number of entries for each day.

public class Main {
    private static HashMap<String, Integer> roster = new HashMap<>();

    //TODO: add your methods here

    public static void main(String[] args) {
        addToRoster("Monday"); // i.e., one person signed up for Monday
        addToRoster("Wednesday"); // i.e., one person signed up for Wednesday
        addToRoster("Wednesday"); // i.e., another person signed up for Wednesday
        addToRoster("Friday");
        addToRoster("Monday");
        printRoster();
    }

}

Monday => 2
Friday => 1
Wednesday => 2

Hint



Resources




Guidance for the item(s) below:

Software engineers often have to write developer documentation to explain their work to others. One important objective of developer documentation is to explain the design and the implementation of the software, which usually uses diagrams as models of the design being described.

Let's learn what models are, and how they are useful even beyond mere documentation.

[W6.3] Design: Models

W6.3a

Design → Modelling → Introduction → What

Can explain models

A model is a representation of something else.

A class diagram is a model that represents a software design.

A model provides a simpler view of a complex entity because a model captures only a selected aspect. This omission of some aspects implies models are abstractions.

A class diagram captures the structure of the software design but not the behavior.

Multiple models of the same entity may be needed to capture it fully.

In addition to a class diagram (or even multiple class diagrams), a number of other diagrams may be needed to capture various interesting aspects of the software.


W6.3b

Design → Modelling → Introduction → How

Can explain how models are used

In software development, models are useful in several ways:

a) To analyze a complex entity related to software development.

Some examples of using models for analysis:

  1. Models of the can be built to aid the understanding of the problem to be solved.
  2. When planning a software solution, models can be created to figure out how the solution is to be built. An architecture diagram is such a model.

b) To communicate information among stakeholders. Models can be used as a visual aid in discussions and documentation.

Some examples of using models to communicate:

  1. You can use an architecture diagram to explain the high-level design of the software to developers.
  2. A business analyst can use a use case diagram to explain to the customer the functionality of the system.
  3. A class diagram can be reverse-engineered from code so as to help explain the design of a component to a new developer.

c) As a blueprint for creating software. Models can be used as instructions for building software.

Some examples of using models as blueprints:

  1. A senior developer draws a class diagram to propose a design for an OOP software and passes it to a junior programmer to implement.
  2. A software tool allows users to draw UML models using its interface and the tool automatically generates the code based on the model.
Model Driven Development extra

Exercises




Guidance for the item(s) below:

This module covers only two types of diagrams: class/object diagrams (CD/OD) -- which model a structural aspect of an OOP design, and sequence diagrams (SD) -- which model a behavioral aspect. This week, let's learn the basic CD/OD notation.

We recommend you try the relevant post-lecture quizzes as you read each sections below. In these quizzes, you will be able to see the answers immediately after completing the quiz.

[W6.4] Class/Object Diagrams: Basics

Video

W6.4a

Design → Modelling → Modelling Structure → OO structures

Design → OOP → Classes → Basic


Can explain structure modeling of OO solutions

An OO solution is basically a network of objects interacting with each other. Therefore, it is useful to be able to model how the relevant objects are 'networked' together inside a software i.e. how the objects are connected together.

Given below is an illustration of some objects and how they are connected together. Note: the diagram uses an ad-hoc notation.

Note that these object structures within the same software can change over time.

Given below is how the object structure in the previous example could have looked like at a different time.

However, object structures do not change at random; they change based on a set of rules, as was decided by the designer of that software. Those rules that object structures need to follow can be illustrated as a class structure i.e. a structure that exists among the relevant classes.

Here is a class structure (drawn using an ad-hoc notation) that matches the object structures given in the previous two examples. For example, note how this class structure does not allow any connection between Genre objects and Author objects, a rule followed by the two object structures above.

UML Object Diagrams are used to model object structures and UML Class Diagrams are used to model class structures of an OO solution.

Here is an object diagram for the above example:

And here is the class diagram for it:


W6.4b

Design → Modelling → Modelling Structure → Class diagrams - basic

Can use basic-level class diagrams

Contents of the panels given below belong to a different chapter; they have been embedded here for convenience and are collapsed by default to avoid content duplication in the printed version.

UML Class Diagrams → Introduction → What


Classes form the basis of class diagrams.

UML Class Diagrams → Classes → What


UML Class Diagrams → Class-Level Members → What


Associations are the main connections among the classes in a class diagram.

OOP Associations → What


UML Class Diagrams → Associations → What


The most basic class diagram is a bunch of classes with some solid lines among them to represent associations, such as this one.

An example class diagram showing associations between classes.

In addition, associations can show additional decorations such as association labels, association roles, multiplicity and navigability to add more information to a class diagram.

UML Class Diagrams → Associations → Labels


UML Class Diagrams → Associations → Roles


OOP Associations → Multiplicity


UML Class Diagrams → Associations → Multiplicity


OOP Associations → Navigability


UML Class Diagrams → Associations → Navigability


Here is the same class diagram shown earlier but with some additional information included:

Exercises

Which association notations are shown?


Explain Class Diagram


Draw Class Diagram for Box etc.




W6.4c

Tools → UML → Class Diagrams → Associations as attributes

Can show an association as an attribute

An association can be shown as an attribute instead of a line.

Association multiplicities and the default value can be shown as part of the attribute using the following notation. Both are optional.

name: type [multiplicity] = default value

The diagram below depicts a multi-player Square Game being played on a board comprising of 100 squares. Each of the squares may be occupied with any number of pieces, each belonging to a certain player.

A Piece may or may not be on a Square. Note how that association can be replaced by an isOn attribute of the Piece class. The isOn attribute can either be null or hold a reference to a Square object, matching the 0..1 multiplicity of the association it replaces. The default value is null.

The association that a Board has 100 Squares can be shown in either of these two ways:

Show each association as either an attribute or a line but not both. A line is preferred as it is easier to spot.


Guidance for the item(s) below:

Object diagrams complement class diagrams, and therefore, they are covered together with class diagrams.

W6.4d

Design → Modelling → Modelling Structure → Object diagrams

Can use basic object diagrams

UML → Object Diagrams → Introduction


Object diagrams can be used to complement class diagrams. For example, you can use object diagrams to model different object structures that can result from a design represented by a given class diagram.

UML → Object Diagrams → Objects


UML → Object Diagrams → Associations


Exercises

Draw an Object Diagram for Box etc.




W6.4e

Tools → UML → Object versus class diagrams

Can distinguish between class diagrams and object diagrams

Compared to the notation for class diagrams, object diagrams differ in the following ways:

  • Show objects instead of classes:
    • Instance name may be shown
    • There is a : before the class name
    • Instance and class names are underlined
  • Methods are omitted
  • Multiplicities are omitted. Reason: an association line in an object diagram represents a connection to exactly one object (i.e., the multiplicity is always 1).

Furthermore, multiple object diagrams can correspond to a single class diagram.

Both object diagrams are derived from the same class diagram shown earlier. In other words, each of these object diagrams shows ‘an instance of’ the same class diagram.

When the class diagram has an inheritance relationship, the object diagram should show either an object of the parent class or the child class, but not both.

Suppose Employee is a child class of the Person class. The class diagram will be as follows:

Now, how do you show an Employee object named jake?

  • This is not correct, as there should be only one object.

  • This is OK.

  • This is OK, as jake is a Person too. That is, we can show the parent class instead of the child class if the child class doesn't matter to the purpose of the diagram (i.e., the reader of this diagram will not need to know that jake is in fact an Employee).

Association labels/roles can be omitted unless they add value (e.g., showing them is useful if there are multiple associations between the two classes in concern -- otherwise you wouldn't know which association the object diagram is showing)

Consider this class diagram and the object diagram:

We can clearly see that both Adam and Eve lives in hall h1 (i.e., OK to omit the association label lives in) but we can't see if History is Adam's major or his minor (i.e., the diagram should have included either an association label or a role there). In contrast, we can see Eve is an English major.

Exercises