computer science 209 software development iterators
TRANSCRIPT
Implementing Equals
public boolean equals(Object other){ if (this == other) return true; if (! (other instanceof LinkedStack)) return false; LinkedStack<E> otherStack = (LinkedStack<E>)other; if (this.size() != otherStack.size()) return false; return this.containsAll(otherStack) && otherStack.containsAll(this);}
Can result in quadratic running time
What if the two stacks contain the same elements, but they are not in the same order?
Implementing Equals
public boolean equals(Object other){ if (this == other) return true; if (! (other instanceof LinkedStack)) return false; LinkedStack<E> otherStack = (LinkedStack<E>)other; if (this.size() != otherStack.size()) return false; for (int i = 0; i < this.size(); i++) if (! this.list.get(i).equals(otherStack.list.get(i))) return false; return true;}
get runs in constant time for ArrayList but in linear time for LinkedStack
Results in quadratic running time for LinkedStack.equals
Implementing Equals
public boolean equals(Object other){ if (this == other) return true; if (! (other instanceof LinkedStack)) return false; LinkedStack<E> otherStack = (LinkedStack<E>)other; if (this.size() != otherStack.size()) return false; Iterator<E> otherIter = otherStack.iterator(); for (E thisElement : this) if (! thisElement.equals(otherIter.next())) return false; return true;}
next runs in constant time for any collection’s iterator
Results in linear running time for any equals
The Iterator Interface
public interface Iterator<E>{
public boolean hasNext() public E next() public void remove()}
remove deletes the object most recently accessed with next
remove must be included in the implementing class, but need not be supported (can throw an UnsupportedOperationException)
Using an Iterator
// add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
Every collection class that supports an iterator must provide aniterator method.
This method returns an instance of a class that implements the Iterator interface
anIterator aCollectionA sequence of elements
// add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ SomeType obj = iter.next(); System.out.println(obj);}
Using an Iterator
D D Dcollection
iterator
// add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ SomeType obj = iter.next(); System.out.println(obj);}
Using an Iterator
D D Dcollection
iterator
// add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ SomeType obj = iter.next(); System.out.println(obj);}
Using an Iterator
D D Dcollection
iterator
// add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ SomeType obj = iter.next(); System.out.println(obj);}
Using an Iterator
D D Dcollection
iterator
// add a bunch of objects to col
for (SomeType obj : col) System.out.println(obj);
Iterable and the for-each Loop
D D Dcollection
iterator
If col implements the Iterable interface, the client can use a for-each loop instead
Use in AbstractCollectionabstract public class AbstractCollection<E> implements Collection<E>{ public void clear(){ Iterator<E> iter = this.iterator(); while (iter.hasNext()){ iter.next(); iter.remove(); } }
public boolean remove(Object o){ Iterator<E> iter = this.iterator(); while (iter.hasNext()) if (iter.next().equals(o)){ iter.remove(); return true; } return false; }
public boolean hasNext()
public E next()
Preconditions on Methods
hasNext has no preconditions
next has two preconditions:• hasNext returns true• the underlying collection has not been modified by one of that collection’s mutators during the lifetime of that iterator
// Add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ SomeType obj = iter.next(); <blah blah blah>}
SomeType obj = iter.next(); // This should cause an exception
Error: Run Out of Elements
// Add a bunch of objects to col
Iterator<SomeType> iter = col.iterator();
while (iter.hasNext()){ col.removeLast(); SomeType obj = iter.next(); // This should cause an exception}
Error: Inconsistent Data
Using mutators in conjunction with iterators is a bad practice
An Iterator Implementation
The iterator method is in the Iterable interface
public interface TrueStack<E> extends Collection<E>{
public E pop();
public void push(E newElement);
public E peek();}
<<Interface>>Collection
<<Interface>>Iterable
<<Interface>>TrueStack
public class ArrayStack<E> extends AbstractCollection<E> implements TrueStack<E>{
private List<E> list;
// Code for constructors, push, pop, peek, size, and add
public Iterator<E> iterator(){ return list.iterator(); }
An Iterator Implementation
Problem: a list’s iterator supports the remove method
Another Design Strategy
• By using the list’s iterator, we expose it to the client (Law of Demeter?)
• Let’s use it, but wrap our own iterator object around it
• That allows us to control what’s supported and what’s not
public class ArrayStack<E> extends AbstractCollection<E> implements TrueStack<E>{
private List<E> list;
// Code for push, pop, peek, size, and add
// Code for the iterator method
// Code for the class that implements the Iterator // interface}
An Iterator Implementation
Define the iterator class as a private inner class.
public Iterator<E> iterator(){ return new StackIterator<E>(this.iterator());}
private class StackIterator<E> implements Iterator<E>{
public boolean hasNext(){ return false; }
public E next(){ return null; }
public void remove(){ }
}
The Implementing Class
NestedwithinArrayStack
public Iterator<E> iterator(){ return new StackIterator<E>(list.iterator());}
private class StackIterator<E> implements Iterator<E>{
private Iterator<E> iter;
private StackIterator(Iterator<E> iter){ this.iter = iter; }
// Other methods }
The Implementing Class
NestedwithinArrayStack