Homework #3
due Monday, February 13, 10:00 PM

In this homework, you will complete the implementation of a simple GUI application to gravitational simulations. You will also use a collection class with an interface based on Java's library collection system.

Concepts

In this week, you will work with several concepts that don't have their own chapter in the textbook.

Interfaces

A Java ``interface'' is a special kind of ``abstract class.'' A Java interface specifies a set of (public) operations that an ADT might be expected to implement. An ADT implementation signals its adherence to the interface by adding ``implements $I$'' to the class header, where $I$ is the name of the interface.

A Java variable (field, parameter or local) may have an interface as a type. Of course the variable is not an instance of this type, since interfaces are abstract--they don't provide any implementation. Instead they are instances of some class that implements the interface. In Java, it is considered better to use interfaces for the type of variables or method returns instead of concrete classes since it makes the program more general.

In this assignment, you will need to use an interface called ActionListener and one ``generic'' interface both described later.

Generics

A generic class has type parameters enclosed in angle brackets, for example class ArrayList<T>; here $T$ is the only generic type parameter. Inside the body of the class $T$ can be used as a regular type. When the class is used, you need to instantiate it with an actual type parameter, for instance String or Particle. Writing generic classes is somewhat involved, and so we delay such an assignment until week 6 or 7.

Collections

Soon after Java was released, the need for a standardized collections framework became apparent. Accordingly, Java 1.2 introduced a standard collections framework. Each of the collection classes implements a standard set of operations including the following (among others):

clear()
Remove all elements in the collection;
size()
Return the number of elements in the collection;
add(E x)
Add an element to the collection (where E is the generic type parameter for the elements);
iterator()
Return an iterator (q.v.) over the elements in the container.
We define this set of operations in an interface edu.uwm.cs351.util.Collection<E>. We give an implementation of this interface in class edu.uwm.cs351.util.ArrayList<E>. This class is a stripped down version of the Java library class java.util.ArrayList. For this Homework, don't use the standard Java library Collection or ArrayList.

Iterators

Java's external iterators have the following methods:

hasNext()
Return true if there still remain elements to be returned.
next()
Return the next element in the container. If there is no such element (in which case hasNext() should have returned false), then throw an instance of NoSuchElementException.
remove()
Remove the last element returned by next() from the collection. Throws an instance of class IllegalStateException if next() has not yet been called or if the element has already been removed.
The Iterator interface is generic with the type of the elements in the collection. To access all the elements of a collection, and decide whether to delete them, one can write:

for (Iterator<$T$> it = $c$.iterator(); it.hasNext();) {
   $T$ x = it.next();
   if (we don't want element x any more) it.remove();
}

Java has a special syntax of ``for'' loops to make it easy to use iterators. The shortcut:


for ($T$ $x$ : $c$) {
   ...
}

is short for

for (Iterator _secret = $c$.iterator(); _secret.hasNext();) {
   final $T$ $x$ = _secret.next();
   ...
}

Fail-Fast Iterators

When using standard Java collections, (external) iterators become ``stale'' if the collection changes, except by using the iterator's own remove method. It is not legal to use a stale iterator for anything, even calling hasNext. In other words, if you request an iterator and later add an element to the collection, then you are not allowed to use the iterator again. If you want an iterator, you must request a new one.

Implementors of Java's standard collections are encouraged to provide fail fast implementations of iterators which ``usually'' throw an exception (an instance of ConcurrentModificationException) when a stale iterator is used. A ``fail fast'' implementation is not an absolute requirement.

The stripped-down ArrayList CS 351 library class has this ``feature.''

Anonymous classes

This week, we will work with the ``action listener'' interface:

public interface ActionListener {
  public void actionPerformed(ActionEvent e);
}
One could define a class that implemented this interface and then create an instance of it:
public class MyActionListener implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    // do something
  }
}
...
        new MyActionListener()
But frequently, we don't really care what the name of the class is, we only want to make an instance of it. In that case we can create an instance of an anonymous class using the following syntax:
new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    // do something
  }
}
This looks as if we are creating an instance of the interface, but actually we are creating an instance of a class that is never given a (visible) name. The anonymous class implements the interface and defines the method actionPerformed.

Event Handlers

With Java's graphics model, events are reacted to, rather than detected. In other words, rather than repeatedly asking ``Did someone click my window?'' a Java application program will say ``if someone clicks my window, let me know.'' Then the general event system will call a method when the window is clicked. The object to be notified must implement the required interface.

In our case, we have a few buttons above the window:

Show
Print out (the positions of) all particles in the simulations.
Add Random
Add a randomly moving particle with randomly moving size and color somewhere (random) near the middle of the screen.
Clear
Remove all particles.
Remove Far
Remove all particles greater than 10000 pixels from the center of the screen.
When the window is set up, we ask the system to tell us when the button is pressed using addActionListener, for example:
clearButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
        doClear();
    }
});
The doClear method is a method of the outer class (class Main) which the anonymous class has implicit access to. This feature is very convenient and used frequently in Java programs.

Concurrent Programming without Race Conditions

Our animation programs are multi-threaded programs because the timer/animation thread is different from the thread that handles updating the screen. Programming for this model requires some careful work. We were sloppy in the last homework, but this homework, you will need to be careful to follow these rules:

One important consequence of these two simple rules is that a mutable collection (instance of library class) must not be accessed in multiple threads. The simple solution is to make sure all shared collections are immutable: they never change.

In particular, the collection of particles used in the simulation should never change. How then can one add or remove particles? There's a trick! We make a new collection that is a copy of the list of particles, make changes to it (in one thread) and then install it as the (immutable!) list of particles being simulated. The field that holds the list is mutable (and will be marked ``volatile'').

What You Need To Do

You will need to complete a Main class that creates a gravity simulation window with four buttons as described above. In particular, you will need to use the technique described for updating the collection of particles being simulated without race conditions. You need to use iterators to do the work.

You need to update the Particle ADT to add a ``_name'' field, update the constructor to take the name, and override the toString method to print the name and position. Then the doShow method simply can print the particles, and this overriding will cause the name and position to be printed.

You need to complete the class ManyParticles using a collection class, rather than a sequence.

Files

In $CLASSHOME/src/homework3, we provide the skeleton files for Main.java and ManyParticles.java and also a JAR files of all unchanged classes you need from earlier homework assignments, as well as the stripped down Collection interface and ArrayList implementation.

You will also want to get the file in the solution for Homework #1 that implements the Particle ADT: $CLASSHOME/solution/1/edu/uwm/cs351/Particle.java.

In your Eclipse project in AFS, you should choose ``Project>Properties,'' and then select ``Java Build Path'' and the ``Libraries'' tab. Then press the button ``Add External Jar'' and use the file selector to point to $CLASSHOME/src/homework3/ and then select homework3.jar.

Requirements

At the deadline, your homework/3/ directory must include

As usual, if you create an Eclipse project in your homework/3 directory, then the code will automatically be in the right place.



Footnotes

... ``volatile''1
Or be protected by a synchronization lock, but that is too complicated for us in CS 351. CS 552 and 537 have more information on synchronization.


John Tang Boyland 2012-02-06