NOTE:

Before you start doing any real coding, read the Java Coding Conventions, especially the section on Naming Conventions. You don’t have to inwardly digest every single aspect of these conventions, but try to get a good overview.

It is very important to start coding using the proper naming conventions — they are not optional when it comes to using Java Beans, etc., so let’s start using good habits early!

I will expect you to follow these conventions in all the code you submit to me.

There is one exception: The use of braces in section 7.2 Compound Statements. Their bracing conventions use the following form:

while (!done) {
    statement;
    statement;
}

I prefer the much more readable form:

while (!done) 
{
    statement;
    statement;
}

While you may choose to use the JavaSoft (aka K&R) convention in your personal code, I request you to use my preferred form in the code you submit for these assignments; I find the K&R convention much harder to read, and that adds unnecessary effort to grading assignments.

NOTE: Regardless of brace alignment conventions, I require you to indent statements consistently. Code that does something like:

while (!done) 
    {
    statement;
  statement;
   statement;
}

Is very hard to read, and is often associated with sloppy work. If I encounter this kind of inconsistent formatting, the grade will suffer!

Hint: To ensure that your printer doesn’t turn your nicely aligned statements as seen on the screen into something out of a horror show, you will probably need to set your editor (or IDE editor) to generate spaces in place of tab characters.  Most editors allow you to do that, and furthermore, set where your tab stops will be (I recommend every 2, 3, or 4 spaces, no more, or you’ll tend to use too much horizontal space in your documents).

Part A: A Timer Program

The following program:

package timer;

public class Timer
{
    public void main(String[] args)
    {
        Timer m = new Timer();
    }

    public Timer()
    {
        m_start = new Time(0);
        m_end   = m_start;
        m_end.addSeconds(45);
        System.out.println("Started at " + m_start);
        System.out.println("Ended at   " + m_end);
        System.out.println("Duration = "
                           + m_end.secondsBetween(m_start)
                           + " secs");
    }

    ////////////// Data ///////////////
    private Time m_start, m_end;
}

class Time
{
    public Time(long sec)
    {
        m_sec = sec;
    }

    public void addSeconds(long sec)
    {
        m_sec += sec;
    }

    public long secondsBetween(Time t)
    {
        return m_sec - t.m_sec;
    }

    public String toString()
    {
        return "Time: " + m_sec + " secs";
    }

    /////////////// Data ///////////////
    private long m_sec;
}

is intended to be a rudimentary application (not an applet) which times the duration between two events.

It compiles, but unfortunately refuses to run.

  • Why?
  1. Fix the program so that it will compile and run as an application.

HintThere is a single problem only. It is a simple case of omission — one that is quite a common mistake!

When you finally get the program to run, you will find that it produces the following output:

Started at Time: 45 secs Ended at Time: 45 secs Duration = 0 secs
  • Why?
  1. Fix the program so that it prints out the correct duration.
  2. Now comment out the entire toString() method in the Time class, and recompile and run the program.
  • What happens? How does this change the behavior of the program?
  • Why?

Hint 1Change the lines in the program that read:

System.out.println("Started at " + m_start);
System.out.println("Ended at   " + m_end);

to read:

System.out.println("Started at " + m_start.toString());
System.out.println("Ended at " + m_end.toString());

What effect does this have? Why?

Hint 2Use the IDE help or JDK documentation to find the toString() method. You’ll see that there are many of them, in different classes. Take special note of the toString()/code>< method in the java.lang.Object class.

  • What does this tell you you should probably do, as a regular practice?

Part B: Practice with Strings

In this part of the assignment, you will write a program that accepts a set of strings of people’s names, of the form:

first-name last-name

For example, here’s a set to work with:

"fred bloggs", "MARY STUART",
"eRIC SuttoN", "Francis Bailey",
"Archimedes von trapp", "Abel GRISWOLD",
"Jeffrey Guay", "Alan Swasinski",
"Leroy de la Grange", "Don Ho"

(I’ve intentionally mixed up the case of several of these strings to ensure that you write the code to set the case properly.)

Assume that:

  • the first and last names are separated by a single space character
  • the first name does not contain any spaces
  • the last name may or may not contain one or more spaces (for example, Bailey;  von trapp, de la Grange)
  1. Make sure that each string is properly formatted:

Ensure that each string satisfies the following:

  • the first name has its first character in upper case, and its remaining characters in lower case.
  • the last name has its first character in upper case, and its remaining characters in lower case.
    • However, if the last name contains any spaces, all but its last part should be in lower case, and the first character of the last part should be upcased (for example, “Archimedes von trapp” should result in “Archimedes von Trapp” and not “Archimedes Von trapp”)

Explanation: In some languages, last (family) names may consist of multiple words. For example, in French, the name “de la Grange” is a family name, and in German, the name “von Trapp” is a family name. Typically, the last word is a proper name (often a place name) and so should have its first letter upcased, while the words before it are not proper names (they are often prepositions and/or definite articles) and should not be upcased. The words “de la” in French mean “of the” or “from the”, and the word “von” in German means “of” or “from”.

  1. Sort the names in ascending first name order.  The order should be case insensitive — that is, the sort should not differentiate between upper and lower case characters. Print out the resulting array of strings.
  2. Sort the names in ascending last name order.  The order should be case insensitive. Print out the resulting array of strings.

Here are some skeleton Java sources which I expect you to start from. Note that I’ve already done a lot of the work for you, since the main point of this exercise is for you to learn how to use the String class.   The structure of the program is already present;  all you have to do is fill in the gaps with your code.  Look for [fill in here] indicators, for where you have to supply code.

You can cut and paste from the following Java sources:

package names;

/**
*   Class to represent a person's name.
*/
public class Name implements Comparable
{
    /**
    *   Constructor
    */
    public Name(String first, String last)
    {
        m_first = first;
        m_last = last;
    }

    /**
    *   Returns whether the names are to be sorted
    *   by last name (true) or first name (false)
    */
    public boolean isSortByLast()
    {
        return m_sortByLast;
    }

    /**
    *   Sets whether the names are to be sorted
    *   by last name (true) or first name (false)
    */
    public void setSortByLast(boolean b)
    {
        m_sortByLast = b;
    }

    /**
    *   Compare this object with another object.
    *   (The other object must also be an instance of Name)
    *   NOTE: This comparison is case insensitive;  that is,
    *         letters are sorted regardless of case.
    */
    public int compareTo(Object o)
    {
        Name that = (Name) o;
        String comp1, comp2;
        int result = 0;
        if (m_sortByLast)
        {
            [fill in here]
        }
        else
        {
            [fill in here]
        }
        return result;
    }

    /**
    *   Returns a string of the form:
    *       <first-name> <last-name>
    *   where the two parts of the name are separated by a space.
    */
    public String toString()
    {
        return m_first + " " + m_last;
    }

    ///// Private data //////
    private boolean m_sortByLast = true;
    private String m_first;
    private String m_last;
}
package names;

import java.util.Arrays;

/**
*   Class to test the sorting of Names.
*/
public class NamesTest
{
    /**
    *   Main entry point.
    */
    public static void main(String[] args)
    {
        Name[] names = new Name[m_names.length];
        // populate the array with normalized names
        for (int i = 0; i < m_names.length; i++)
        {
            String name = m_names[i];
            String first = getFirstName(name);
            String last  = getLastName(name);
            names[i] = new Name(first, last);
        }
        // Sort it by last name
        Arrays.sort(names);
        System.out.println("   Names sorted by last name:");
        for (int i = 0; i < names.length; i++)
        {
            System.out.println(names[i]);
        }
        // Sort it by first name
        for (int i = 0; i < names.length; i++)
            names[i].setSortByLast(false);
        Arrays.sort(names);
        System.out.println("   Names sorted by first name:");
        for (int i = 0; i < names.length; i++)
        {
            System.out.println(names[i]);
        }
    }

    /**
    *   Extracts the first name from the specified name,
    *   normalizes it, and then returns it.
    */
    private static String getFirstName(String name)
    {
        // Get rid of any leading or trailing space
            [fill in here]
        // Find the first space
            [fill in here]
        // Extract everything before it as the first name
            [fill in here]
        // Initial cap the entire first name
            [fill in here]
        // Return the first name
    }

    /**
    *   Extracts the last name from the specified name,
    *   normalizes it, and then returns it.
    */
    private static String getLastName(String name)
    {
        // Get rid of any leading or trailing space
            [fill in here]
        // Find the first space
            [fill in here]
        // Extract everything beyond it as the last name
            [fill in here]
        // Find out whether it has an embedded space, 
        // & if it does, find the last one in the name
            [fill in here]
        if ([fill in here]) // No space found
        {
            // No space found, so just Init cap the entire last name
            [fill in here]
        }
        else
        {
            // Space found, so extract the first part
            [fill in here]
            // and lowercase it
            [fill in here]
            // Now extract the last part
            [fill in here]
            // and init cap it
            [fill in here]
            // Then reconstruct the name again, 
            // from the first and last parts
            [fill in here]
        }
        // Return the resulting normalized last name
            [fill in here]
    }

    /**
    *   Utility method to take a string (name) and set the
    *   first character to uppercase, and all the other
    *   characters to lowercase.
    */
    private static String initialCap(String name)
    {
            [fill in here]
    }

    //// Private data /////

    // The initial list of un-normalized names.
    private static String[] m_names =
    {
        "fred bloggs", "MARY STUART",
        "eRIC SuttoN", "Francis Bailey",
        "Archimedes von trapp", "Abel GRISWOLD",
        "Jeffrey Guay", "Alan Swasinski",
        "Leroy de la Grange", "Don Ho"
    };
}

Notes on the Above:

The key to understanding this is to look up the java.lang.Comparable interface in the javadocs (It’s in JDK 1.2 on up).   Class Name implements the Comparable interface, which means that it’s required to implement the method:

public int compareTo(Object o)

This method is used by the Arrays.sort(names) method (also in JDK 1.2 on up).

(Note:  for any of you who aren’t using JDK 1.2 or higher — please upgrade!)

Here’s what the JDK 1.2 docs say about the lang.util.Arrays class’s sort()method (I’ve underlined the critical point):


sort

public static void sort(Object[] a)

Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface. Furthermore, all elements in the array must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the array).
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

The sorting algorithm is a modified mergesort (in which the merge is omitted if the highest element in the low sublist is less than the lowest element in the high sublist). This algorithm offers guaranteed n*log(n) performance, and can approach linear performance on nearly sorted lists.

Parameters:

a – the array to be sorted.

Throws:

ClassCastException – if the array contains elements that are not mutually comparable (for example, strings and integers).

See Also:

Comparable



You’ll note that the above refers to the Comparable interface.

Here’s what the JDK 1.2 docs say about the Comparable interface’s compareTo method:


compareTo

public int compareTo(Object o)

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)

The implementor must also ensure that the relation is transitive:

(x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.

Finally, the implementer must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is “Note: this class has a natural ordering that is inconsistent with equals.”

Parameters:

o – the Object to be compared.

Returns:

a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

Throws:

ClassCastException – if the specified object’s type prevents it from being compared to this Object.