A
Ant...
I have just been trying to create a circular linked list implementation
of the List interface, and have noticed an interesting side effect.
Though the CircularLinkedList satisfies the List contract, it breaks the
other currently implemented collection classes!
The problem is this - the ListIterator interface gives the following
contract for the hasNext() and hasPrevious() methods:
public boolean hasNext()
Returns true if this list iterator has more elements when
traversing the list in the forward direction. (In other words, returns
true if next would return an element rather than throwing an exception.)
public boolean hasPrevious()
Returns true if this list iterator has more elements when
traversing the list in the reverse direction. (In other words, returns
true if previous would return an element rather than throwing an exception.)
Now in a circular list, each of these should by the contract return
false if and only if the List is empty. The problem shows itself when
you try to add a circular list with the appropriate list iterator to
another Collection using the addAll() method - the method uses
hasNext() to constrain the iteration as it adds each element. Hence the
loop never terminates!
I am currently thinking of breaking the contract of either the
ListIterator, to make the list look like a linked list if you are
looking at the hasNext() method, or creating a subclass of the iterator
with hasNext overridden to be returned by the iterator() method.
Two questions:
1) Is there a better way of doing this without breaking the Iterator or
ListIterator contracts?
2) Does anyone else think that this is a flaw in the AbstractCollection
class (which is where the inherited behaviour comes from). Note that
some collections do perform the adding in a more robust way, by calling
the toArray() method of the collection to be added, and adding each
element of the array.
Cheers,
Anthony Roy
of the List interface, and have noticed an interesting side effect.
Though the CircularLinkedList satisfies the List contract, it breaks the
other currently implemented collection classes!
The problem is this - the ListIterator interface gives the following
contract for the hasNext() and hasPrevious() methods:
public boolean hasNext()
Returns true if this list iterator has more elements when
traversing the list in the forward direction. (In other words, returns
true if next would return an element rather than throwing an exception.)
public boolean hasPrevious()
Returns true if this list iterator has more elements when
traversing the list in the reverse direction. (In other words, returns
true if previous would return an element rather than throwing an exception.)
Now in a circular list, each of these should by the contract return
false if and only if the List is empty. The problem shows itself when
you try to add a circular list with the appropriate list iterator to
another Collection using the addAll() method - the method uses
hasNext() to constrain the iteration as it adds each element. Hence the
loop never terminates!
I am currently thinking of breaking the contract of either the
ListIterator, to make the list look like a linked list if you are
looking at the hasNext() method, or creating a subclass of the iterator
with hasNext overridden to be returned by the iterator() method.
Two questions:
1) Is there a better way of doing this without breaking the Iterator or
ListIterator contracts?
2) Does anyone else think that this is a flaw in the AbstractCollection
class (which is where the inherited behaviour comes from). Note that
some collections do perform the adding in a more robust way, by calling
the toArray() method of the collection to be added, and adding each
element of the array.
Cheers,
Anthony Roy