Lab 8: Generics

The goals of this lab are

1. Introduction

As mentioned in the pre-lab reading, the goal of this lab is to practice writing generic classes, and secondarily to practice writing nested classes. Many parts of this will be similar to Project 3, so the emphasis in this description will be on what is different.

2. Set up

As usual, make a directory for this lab. Copy the following code from the public directory.

cp -r /homes/tvandrun/Public/cs245/lab8/. .

Open Eclipse and make a new project from the existing source in your directory.

3. Details

Complete the following steps in order, making sure that the appropriate JUnit tests pass at each step.

A. A first comparator

In the class ComparatorFactory, you'll see a stub for a method lexStringComparator that returns a comparator for strings. The class LexComparatorTest is a JUnit test that tests the comparators returned by that method. Finish the lexStringComparator method (just change one line) so that it returns a comparator that compares strings lexicographically (hint: that's the same way that String.compareTo() would compare them).

Make sure that all the tests in LexComparatorTest pass.

B. Class basics

First, try running the JUnit test suit SLMStringTest. Three test, emptyContainsKey, emptyRemove, and emptyGet should pass out of the box "by luck".

Open the class SortedListMap. You can see the given code, including dummy methods and method stubs. There is also a stub for a Node class and an instance variable for the head node. The node class is a non-static member class, so it is implicitly generic since SortedListMap is generic. Your present task is

Unfortunately no new JUnit tests will pass after this, but make sure that the ones that were passing before still pass.

C. FindNode

Write the method findNode() that will return the node associated with the given key, or null if none exists. Use the comparator to compare keys.

This will make putContainsKey, putGet, and putReplace pass.

D. The iterator.

Write an iterator for this that will return the keys. Do this as an anonymous inner class. Make every effort to do this without looking at in-class examples.

This should make emptyIterator, and populatedIteratorIgnoreOrder pass.

E. Put.

Now the really interesting one. You were given a put method, but it doesn't work right. Re-write this method so that it overwrites the association for the given key (if it already exists), or puts a new association in the right order using the comparator otherwise.

Doing this correctly will make the test populatedIterator pass.

F. Remove.

Now write the remove() method. Since this will be almost verbatim from what you did in project 3, I will give you most of the code for this, for the sake of time. You need to (a) talk through this with your partner and make sure you understand every line, and (b) fix the missing pieces (do not use == or equals(), and make sure you understand why not):

    public void remove(K key) {
        if (head == null) return;
        else if (/* some condition  */) head = head.next;
        else { 
            Node current = head;
            while (current.next != null && /*  some other condition */)
                current = current.next;
            if (current.next != null)
                current.next = current.next.next;
        }
    }

All JUnit tests in SLMStringTest should now pass; newly passed tests are populatedRemove and removeIterator.

G. An alternate comparator for Strings.

The advantage comparators have over comparables is that since one can write many comparators for a class, one can have many ways to order a class. In ComparatorFactory finish the method consonantsStringComparator which compares two strings alphabetically, case-insensitive, looking only at the consonants. For example, Alice and Luca would be considered equivalent because they have the same consonants, ignoring case. Likewise blaaaaaaaaah and blah would be considered equivalent, and Azekah would come after Ziba. Consider y to be a consonant.

This will take a bit of problem-solving, and you may want to make use of methods from Java's String class. I can think of two approaches: one makes use of String methods toLowerCase(), indexOf(), and of course charAt() and length(); the other approach makes use of toLowerCase(), split() and compareTo().

When you have written this, test the comparator directly with ConsComparatorTest. Then make sure that your SortedListMap works just as well with this comparator as with the other by running SLMConStringTest, which is very much like SLMStringTest except it uses the new comparator.

H. Comparators for different classes

Take a look at SLMDriver. This program uses SortedListMap to associate student records with grade records. Look also at StudentRecord and GradeRecord, which are pretty simple classes. SortedListMap prints a grade report for the students in the gradebook map using one of three comparators for StudentRecords. Write these three comparators as anonymous classes in ComparatorFactory. There are no JUnit tests for these; instead, test each one by commenting out and uncommenting the appropriate lines in SLMDriver and observing the results.


Thomas VanDrunen
Last modified: Tue Nov 3 11:56:09 CST 2015