Reputation: 25
I'm trying to understand how to modify the Iterator of my Linked List to be fail-fast.
I understand what it means for an Iterator to be fail-fast, but I don't know how exactly should I change my implementation to achieve this behavior.
I was thinking about adding a key so for every add, but I don't think it is good enough. It is the first time I'm trying to implement a fail-fast iterator, and I would really appreciate any hint.
My code:
package GenericLinkedList;
import java.util.Iterator;
public class GenericLinkedList<E> implements Iterable<E> {
private Node<E> head;
public void pushFront(E data){
head = new Node<>(data, head);
}
public E popFront(){
E dataHead = head.data;
head = head.next;
return dataHead;
}
public int size(){
int counter = 0;
for(E element : this){
++counter;
}
return counter;
}
public boolean isEmpty(){
return (null == head);
}
public Iterator<E> find(E data){
IteratorIMP iter = new IteratorIMP(head);
for(E element : this){
if(element.equals(data)){
return iter;
}
iter.next();
}
return null;
}
public static <E> GenericLinkedList<E> merge(GenericLinkedList<E> firstList, GenericLinkedList<E> secondList){
GenericLinkedList<E> mergeList = new GenericLinkedList<E>();
for(E element : firstList){
mergeList.pushFront(element);
}
for(E element : secondList){
mergeList.pushFront(element);
}
return newReverse(mergeList);
}
public static <E> GenericLinkedList<E> newReverse(GenericLinkedList<E> list){
GenericLinkedList<E> reverseList = new GenericLinkedList<E>();
for(E element : list){
reverseList.pushFront(element);
}
return reverseList;
}
private static class Node<T> {
private Node<T> next;
private T data;
private Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
private class IteratorIMP implements Iterator<E> {
Node<E> node;
private IteratorIMP(Node<E> start){
node = start;
}
@Override
public boolean hasNext() {
return (node != null);
}
@Override
public E next() {
E data = node.data;
node = node.next;
return data;
}
}
@Override
public Iterator<E> iterator() {
IteratorIMP iter = new IteratorIMP(head);
return iter;
}
}
Upvotes: 1
Views: 99
Reputation: 29028
Fail-fast implementation of the Iterator
insures that it would raise an exception if there's an evidence that the collection is being structurally modified (an element was added or removed) during the iteration process, because in such a case, iterator might not be able to reflect the actual state of the collection.
The common approach is to introduce two counters of modifications:
modCount
, which would be incremented whenever list gets modified via pushFront()
, popFront()
, etc.Iterator
- expectedModCount
.If during the next()
call turns out that modCount
and expectedModCount
variables are not equal, that means that there has been a modification after the iterator was created. In such a case, fail-fast Iterators from the JDK would throw ConcurrentModificationException
.
public class GenericLinkedList<E> implements Iterable<E> {
private Node<E> head;
private int modCount;
public void pushFront(E data) {
modCount++; // list is being modified - incrementing the count
head = new Node<>(data, head);
}
public E popFront() {
modCount++; // list is being modified - incrementing the count
E dataHead = head.data;
head = head.next;
return dataHead;
}
// ...
private class IteratorIMP implements Iterator<E> {
private Node<E> node;
private final int expectedModCount;
private IteratorIMP(Node<E> start) {
this.node = start;
this.expectedModCount = GenericLinkedList.this.modCount;
}
// ...
@Override
public E next() {
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
E data = node.data;
node = node.next;
return data;
}
}
}
Upvotes: 1