Thurs, Apr 6.

Iterators using Inner Classes

We have seen above how private inner classes can represent sub-objects, but we saw that the users ended up not being able to directly access the sub-object.  For an iterator, we want the using code to use the Iterator object directly.  How to proceed?

Iterator is an interface, and so no objects of that exact type can be instantiated.  In all cases of “Iterator objects”, we actually have an object that ISA Iterator, via inheritance.

The trick is to have a private inner class that implements Iterator, but itself is of a class unknown to the using code.

See this on pg. 522--LocalIterator is a private class, but MyContainer "iterator()" method returns LocalIterator as an Iterator, public interface, so caller can use it as an Iterator.

This is the setup of the final simple example of Weiss, on pg. 522.  You should add remove() to the implementation of LocalIterator to implement the real JDK Iterator interface.  Apparently Weiss’s package has a simpler Iterator interface. 

See Figure 15.9 for the simpler version of the code of Figure 15.8.  Figure 15.9 shows how easy it is to refer to the outer object’s private fields (size, items) from the inner class code.

Recall the idea that an inner class is like a bump on a log.:  here the log is a List, say, and the bump moves along it allowing us to get to the various elements.

Note that we can have multiple Iterators going at the same time:  Figure 15.7 illustrates this abstractly.

Example: find the most duplicated String from a Collection C of Strings
Algorithm
Initialize maxCount = 0, maxString = null
Get an iterator itr1 over C
    itr1 finds element s
    Get an iterator itr2 over C, count duplicates of s in C
     if (count > maxCount) {
          maxCount = count;
          maxString = s;
     }

<Picture of log-like list with two bumps>

Note this algorithm is O(N*N).  Actually we can do better by sorting the Strings (O(NlogN) and then scanning the array once.

We can see that the MyContainer example can give out multiple iterators.  Each contains its own "current" value.  It is convenient that Weiss's Iterator interface doesn't have "remove()", because that's the hard thing to get right.

Recall that the Robot class knew where its arm objects were, but MyContainer doesn't keep track of its Iterator objects.  That's typical of containers and their iterators.

The JDK Collection classes are very careful about how iterators work when the Collection changes during the iteration.
public class TestArrayList {
    public static void main( String[] args ) {
        ArrayList<String> arr = new ArrayList<String>();
        arr.add("foo");
        arr.add("bar");
        arr.add("foo2");
        Iterator<String> itr = arr.iterator();
        String s = itr.next();  // or leave this out
        arr.remove("foo2");
        itr.next();  // throws
    }
}
dbtest(11)% java TestArrayList
Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
        at java.util.AbstractList$Itr.next(AbstractList.java:420)
        at TestArrayList.main(TestArrayList.java:12)

Similarly if one iterator does a remove, the other will throw when it tries to move.
If you do the remove before creating the iterator, all will work.  

So how does this work?
Answer: the ArrayList object is keeping track of edits to itself by an edit count, and when an iterator is created, it stores the initial modCount, and later compares it to its original one.

So the code on pg. 522 is too simplistic for a JDK class--surely MyContainer has an "add" or "insert" method that modifies its contents...

But the inner class part of this code is fine.  Just need to keep track of edits, make iterator throw when appropriate.

JDK ArrayList Implementataion

Class hierarchy:
Object
  AbstractCollection
     AbstractList <--but Weiss's implementation doesn't have this level
         ArrayList

The book looks at AbstractCollection first--some common code for many collections, or default code begging for overrides--
isEmpty--can always be done by size()
clear--can always be done by iteration + remove, but there might be a better way
add--shows what should happen if no real "add" operation is appropriate, otherwise override

contains, remove--full sequential search, note use of element equals  (override if possible to do better)  We are of course using the equals of the object's runtime class, assuming it's there.  Recall the trickiness of getting this right with inheritance.

toArray-- primitive one is straightforward, but parametrized one uses reflection
                  Note that we need <AnyType> IS-A <OtherType> to allow the element copy.
    Ex.   a1 = ArrayList of Circles
            Shape[] a0 = new Shape[1];  // set up model of what we want
         Shape[] shapes =  a1.toArray(a0);
All we're getting out of all of this is type checking at compile time and avoidance of downcasts.  We could put
  Shape[] shapes = (Shape [])a1.toArray();
and the downcast will work at runtime because a1 has Circles in it.

toString--uses StringBuilder, the newer faster version of StringBuffer--read about it on pg. 528.

ArrayList itself: extends AbstractCollection<AnyType> implements List<AnyType>     a little simpler than JDK

has one array "theItems", size, modCount for iterators
size vs. array size:  sometimes the array won't be all used.

clear--does override

get, set--see O(1)

Note that set doesn't increment modCount--no change to *data structure*, just value held in it.

contains, remove--both call helper findPos, which checks for matching nullness as well as .equals.

remove(idx) moves elements down, but doesn't shrink array itself.

ListIterator for ArrayList

Iterators--recall that the current position is between two elements of the list (positions 1, 2, ..., n-1), or before all elements (position 0), or after al (position n).

private inner class as expected
expectedModCount = initial modCount from outer object
   
What's this nextCompleted, prevCompleted for?

Go back to ListIterator contract, pg. 221:
remove:   Removes the last item returned by next or previous.  Can only be called once after next or previous.

That means we have to track next and previous and disallow sequences like

next, remove, remove
          ^removes element returned by next
                          ^ it's gone!

whereas   next, remove, previous, remove  is OK
                          ^ removes element e1 returned by next, closing up list
                                           ^ steps across element that used to be before e1
                                                          ^ removes element that used to be before e1

Thus each "next" or "previous" authorizes a possible remove and must be remembered in the iterator.

We can show that nextCompleted is true if and only if next has been called and no other calls to previous or remove have since been called., so it's OK to do a remove, which will remove the element returned by that next call.

Similarly with prevCompleted.

So only one of nextCompleted and prevCompleted can be true, and it shows which one (of the two around the current position) should be removed when a remove comes in.

Look at code to prove the definitions and see the action in remove.