ListIterator methods
ListIterator
is implemented only by the classes that implement the List
interface (ArrayList
, LinkedList
, and Vector
). ListIterator provides the following.Result | Method | Description |
---|---|---|
Forward iteration | ||
b = | it.hasNext() | true if there is a next element in the collection. |
obj = | it.next() | Returns the next object. |
Backward iteration | ||
b = | it.hasPrevious() | true if there is a previous element. |
obj = | it.previous() | Returns the previous element. |
Getting the index of an element | ||
i = | it.nextIndex() | Returns index of element that would be returned by subsequent call to next(). |
i = | it.previousIndex() | Returns index of element that would be returned by subsequent call to previous(). |
Optional modification methods. UnsupportedOperationException thrown if unsupported. | ||
it.add(obj) | Inserts obj in collection before the next element to be returned by next() and after an element that would be returned by previous() . | |
it.set() | Replaces the most recent element that was returned by next or previous() . | |
it.remove() | Removes the most recent element that was returned by next() or previous() . |
So its of form:
public interface ListIterator extends Iterator {
boolean hasNext();
Object next();
boolean hasPrevious();
Object previous();
int nextIndex();
int previousIndex();
void remove(); // Optional
void set(Object o); // Optional
void add(Object o); // Optional
}
The three methods that
ListIterator
inherits from Iterator
(hasNext
, next
, and remove
) are intended to do exactly the same thing in both interfaces. The hasPrevious
and previous
operations are exact analogues of hasNext
and next
. The former operations refer to the element before the (implicit) cursor, whereas the latter refer to the element after the cursor. The previous
operation moves the cursor backwards whereas next
moves it forwards.Here's the standard idiom for iterating backwards through a list:
Note the argument tofor (ListIterator i=l.listIterator(l.size()); i.hasPrevious(); ) {
Foo f = (Foo) i.previous();
...
}
listIterator
in the above idiom. The List
interface has two forms of the listIterator
method. The form with no arguments returns a ListIterator
positioned at the beginning of the list, and the form with an int
argument returns a ListIterator
positioned at the specified index. The index refers to the element that would be returned by an initial call to next
. If the index value of n
is used, then the initial call to next
would return null, since it would point just past the end of the list. An initial call to previous
would return the element whose index was index-1
.In a list of length
n
, there are n+1
valid values for index
, from 0
to n
, inclusive. Intuitively speaking, the cursor is always between two elements, the one that would be returned by a call to
previous
and the one that would be returned by a call to next
. The n+1
valid index
values correspond to the n+1
"gaps" between elements, from the gap before the first element to the gap after the last one. The diagram below shows the five possible cursor positions in a list containing four elements. Element(0) Element(1) Element(2) Element(3)Calls to
^ ^ ^ ^ ^
Index: 0 1 2 3 4
next
and previous
can be intermixed, but you have to be a bit careful. The first call to previous
after a sequence of calls to next
returns the same element as the last call to next
. Similarly, the first call to next
after a sequence of calls to previous
returns the same element as the last call to previous
. This will become obvious if you stare at the foregoing text long enough. If it doesn't, go get yourself a steaming hot mug of Java, and try again.nextIndex and previousIndex
It should come as no surprise that the
nextIndex
method returns the index of the element that would be returned by a subsequent call to next
, and previousIndex
returns the index of the element that would be returned by a subsequent call to previous
. These calls are typically used for one of two purposes: To report the position where something was found, or to record the position of the ListIterator
so that another ListIterator
with identical position can be created. It should also come as no surprise that the number returned by
nextIndex
is always one greater than the number returned by previousIndex
. This implies the behavior of the two boundary cases: a call to previousIndex
when the cursor is before the initial element returns -1
, and a call to nextIndex
when the cursor is after the final element returns list.size()+1
. To make all of this concrete, here's a possible implementation of List.indexOf
: Note that thepublic int indexOf(Object o) {
for (ListIterator i = listIterator(); i.hasNext(); )
if (o==null ? i.next()==null : o.equals(i.next()))
return i.previousIndex();
return -1; // Object not found
}
indexOf
method returns i.previousIndex()
though it is traversing the list in the forward direction. This is because i.nextIndex()
would return the index of the element that we are about to examine, and we want to return the index of the element that we just examined. The Iterator
interface provides the remove
operation to remove from the Collection
the last element returned by next
. The ListIterator
interface provides two additional operations to modify the list: set
and add
. The set
method "overwrites" the last element returned by next
or previous
with the specified element. It is demonstrated by the following polymorphic algorithm to replace all occurrences of one specified value with another: The only bit of trickiness in this example is the equality test betweenpublic static void replace(List l, Object val, Object newVal) {
for (ListIterator i = l.listIterator(); i.hasNext(); )
if (val==null ? i.next()==null : val.equals(i.next()))
i.set(newVal);
}
val
and i.next
. We have to special-case an val
value of null
in order to prevent a NullPointerException
. The add
method inserts a new element into the list, immediately before the current cursor position. This method is illustrated in the following polymorphic algorithm to replace all occurrences of a specified value with the sequence of values contained in the specified list: public static void replace(List l, Object val, List newVals) {
for (ListIterator i = l.listIterator(); i.hasNext(); ) {
if (val==null ? i.next()==null : val.equals(i.next())) {
i.remove();
for (Iterator j = newVals.iterator(); j.hasNext(); )
i.add(j.next());
}
}
}
BAD BAD BAD
- Q: What does this loop do? Note mixing of iterator with index.
- A: It throws an exception when it goes beyond the end.
- After
hasNext()
returns true, the only way to advance the iterator is to callnext()
. But the element is retrived withget()
, so the iterator is never advanced.hasNext()
will continue to always be true (ie, there is a first element), and eventually theget()
will request something beyond the end of the ArrayList. Use either the iterator scheme.for (Iterator<String> it = alist.iterator(); it.hasNext(); ) {
Or the indexing scheme, but don't mix them.
System.out.println(it.next());
}for (int i=0; i < alist.size(); i++) {
System.out.println(alist.get(i));
}
ArrayList<String> alist = new ArrayList<String>();
// . . . Add Strings to alist
int i = 0;
for (Iterator<String> it = alist.iterator(); it.hasNext(); ) {
System.out.println(alist.get(i++));
}
No comments:
Post a Comment