Java迭代器iterator之大战石家庄疫情

361 阅读3分钟

大家都看新闻了,最近石家庄疫情有新增。希望国际站能早日战胜!

踩坑迭代器

是不是有人在遍历删除List集合里的数据的时候遇到了某些问题?

简单用法

Collection<String> collection = new ArrayList<String>();
collection.add("Dao");
collection.add("Sen");
// 迭代器
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
	String item = iterator.next();
	System. out.println(item);
    // 打印完如果需要从集合删除
    iterator.remove()
}

介绍常用的三个方法

  • hasNext():返回boolean,表示判断是否存在下一个元素
  • next():返回集合当前元素
  • remove():删除当前元素

来看一下ArrayList的iterator实现方式

private class Itr implements Iterator<E> {
       // 将要next返回元素的索引
        int cursor = 0;
       // 当前返回的元素的索引,初始值-1
        int lastRet = -1;

        /**
        * The modCount value that the iterator believes that the backing
        * List should have.  If this expectation is violated, the iterator
        * has detected concurrent modification.
        */
        int expectedModCount = modCount;

        public boolean hasNext() {
            // 由于cursor是将要返回元素的索引,也就是下一个元素的索引,和size比较是否相等,也就是判断是否已经next到最后一个元素
            return cursor != size();
       }

        public E next() {
            checkForComodification();
           try {
              // 根据下一个元素索引取出对应元素
              E next = get( cursor);
              // 更新lastRet为当前元素的索引,cursor加1
               lastRet = cursor ++;
              // 返回元素
               return next;
           } catch (IndexOutOfBoundsException e) {
              checkForComodification();
               throw new NoSuchElementException();
           }
       }

        public void remove() {
           // remove前必须先next一下,先取得当前元素
           if (lastRet == -1)
               throw new IllegalStateException();
            checkForComodification();

           try {
              AbstractList. this.remove(lastRet );
               // 确保lastRet比cursor小、理论上永远lastRet比cursor小1
               if (lastRet < cursor)
                  // 由于删除了一个元素cursor回退1
                  cursor--;
               // 重置为-1
               lastRet = -1;
               expectedModCount = modCount ;
           } catch (IndexOutOfBoundsException e) {
               throw new ConcurrentModificationException();
           }
       }

        final void checkForComodification() {
           if (modCount != expectedModCount)
               throw new ConcurrentModificationException();
       }
}

再来看看LinkedList的Iterator实现

LinkedList的Iterator实现定义在AbstracSequentialtList中,实现在AbstractList中

AbstracSequentialtList的定义:
public Iterator<E> iterator() {
	return listIterator();
}
AbstractList的实现:
public ListIterator<E> listIterator() {
        return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
	if (index<0 || index>size())
		throw new IndexOutOfBoundsException( "Index: "+index);

        return new ListItr(index);
}
ListItr实现:
private class ListItr implements ListIterator<E> {
        // 最后一次返回的节点,默认位header节点
        private Entry<E> lastReturned = header;
        // 将要返回的节点
        private Entry<E> next ;
        // 将要返回的节点index索引
        private int nextIndex;
        private int expectedModCount = modCount;

       ListItr( int index) {
           // 索引越界检查
           if (index < 0 || index > size)
               throw new IndexOutOfBoundsException( "Index: "+index+
                                             ", Size: "+size );
           // 简单二分,判断遍历的方向
           if (index < (size >> 1)) {
               // 取得index位置对应的节点
               next = header .next;
               for (nextIndex =0; nextIndex<index; nextIndex++)
                  next = next .next;
           } else {
               next = header ;
               for (nextIndex =size; nextIndex>index; nextIndex --)
                  next = next .previous;
           }
       }

        public boolean hasNext() {
           // 根据下一个节点index是否等于size,判断是否有下一个节点
           return nextIndex != size;
       }

        public E next() {
           checkForComodification();
           // 遍历完成
           if (nextIndex == size)
               throw new NoSuchElementException();

           // 赋值最近一次返回的节点
           lastReturned = next ;
           // 赋值下一次要返回的节点(next后移)
           next = next .next;
           // 将要返回的节点index索引+1
           nextIndex++;
           return lastReturned .element;
       }

        public boolean hasPrevious() {
           return nextIndex != 0;
       }

       //  返回上一个节点(双向循环链表嘛、可以两个方向遍历)
        public E previous() {
           if (nextIndex == 0)
               throw new NoSuchElementException();

           lastReturned = next = next. previous;
           nextIndex--;
           checkForComodification();
           return lastReturned .element;
       }

        public int nextIndex() {
           return nextIndex ;
       }

        public int previousIndex() {
           return nextIndex -1;
       }

        public void remove() {
            checkForComodification();
            // 取出当前返回节点的下一个节点
            Entry<E> lastNext = lastReturned.next ;
            try {
                LinkedList. this.remove(lastReturned );
            } catch (NoSuchElementException e) {
                throw new IllegalStateException();
            }
           // 确认下次要返回的节点不是当前节点,如果是则修正
           if (next ==lastReturned)
                next = lastNext;
            else
             // 由于删除了一个节点,下次要返回的节点索引-1
               nextIndex--;
           // 重置lastReturned为header节点
           lastReturned = header ;
           expectedModCount++;
       }

        public void set(E e) {
           if (lastReturned == header)
               throw new IllegalStateException();
           checkForComodification();
           lastReturned.element = e;
       }

        public void add(E e) {
           checkForComodification();
           lastReturned = header ;
           addBefore(e, next);
           nextIndex++;
           expectedModCount++;
       }

        final void checkForComodification() {
           if (modCount != expectedModCount)
               throw new ConcurrentModificationException();
       }
}

介绍完毕,希望国际站疫情也到此为止。