Iterator接口

public interface Iterator<E> {

    boolean hasNext();

    E next();

    void remove();
}

访问元素前需要使用hasNext进行判断是否有元素存在,如果有再通过next操作获取,直接使用next操作而不进行hasNext检测,当到达末尾时会抛出NoSuchElement异常

Iterator的remove操作

好久没有看JDK代码了,今天翻看Java Core看到迭代器里面的注意点,居然一点都回忆不起来了。先看如下代码:

        Iterator<String> iter = list.iterator();
String s = iter.next();
iter.remove();

那么这里iter.remove()删除的是哪个元素,删除的是列表中的第一个元素,通用一点来讲是迭代器上一次next()所返回的那个元素。又有如下代码:

        Iterator<String> iter = list.iterator();
String s = iter.next();
iter.remove();
iter.remove();

如果去实际运行的话会报:java.lang.IllegalStateException异常即,每次remove都应该有对应的一次next,其实就是两两配对的,remove的就是next返回的那个元素。

从AbstractList的源码中可以看到Iterator的一个基本实现:

 private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0; /**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
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() {
return cursor != size();
} public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
} public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

可以看到有lastRet和cursor两个变量,前者用于代表next()操作返回的元素的索引,后者用于表示下一次next()调用是应该返回的元素的索引值。每当一次remove操作后lastRet就被清空了,同时cursor--,因为lastRet对应的元素在cursor前面,而此时其被remove了,那么cursor的值必然要减一。其实这里的迭代器实现都基本上被AbstractList的子类覆盖了,如LinkedList,ArrayList。前者不支持随机访问肯定不能用索引值作为获取元素的实现,否则迭代器效率就太低了。

ListIterator(extends Iterator<E>)

List接口除了继承Iterable接口外,还有几个额外的方法(listIterator)用来获取专门针对List的迭代器(即ListIterator)可以看一下LinkedList的迭代器实现:

private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount; ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
} public boolean hasNext() {
return nextIndex < size;
} public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException(); lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
} public boolean hasPrevious() {
return nextIndex > 0;
} public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException(); lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
} public int nextIndex() {
return nextIndex;
} public int previousIndex() {
return nextIndex - 1;
} public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException(); Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
} public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
} public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

对于remove操作的思路大体一致只不过把lastRet换成了一个链表节点lastReturned,在每次remove后也会将其置位null。而在获取元素上不是像父类版本中的那样直接通过get(i)进行获取。迭代器会保存两个相邻的节点指针lastReturned和next。这样当元素被remove掉(lastReturned=null),当再次调用next时由于保存了next指针值,依然可以在链表中移动。

相比于Iterator接口ListIterator接口多了一个add方法,它会把元素放入到迭代器指向的next元素之前的位置,即下一个元素之前的位置。

Iterable接口

public interface Iterable<T> {

    /**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}

如Java Core上所述如果我们实现Iterable接口那么就可以在foreach循环中使用。如

class MyCollection implements Iterable<Integer> {

    @Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
public int count = 0; @Override
public boolean hasNext() { return count < 10;
} @Override
public Integer next() {
return count++;
} @Override
public void remove() {
throw new UnsupportedOperationException();
} };
} } public class Fields implements Const {
public static void main(final String[] args) { MyCollection myCollection = new MyCollection();
for (Integer i : myCollection) {
System.out.println(i);
} }
}

Java 集合:迭代器(Iterator, Iterable)的更多相关文章

  1. Java集合迭代器 Iterator分析

    简介 迭代器是遍历容器的一种常用方法,它屏蔽了容器的实现细节,无需暴露数据结构内部,就可以对容器进行遍历,迭代器本身也是一种设计模式,迭代是一种特殊的遍历方式. Iterator 在java中,迭代器 ...

  2. java集合---迭代器iterator

    一:ArraryList  最终继承超级接口Collection,Colection接口继承Iterator接口. public interface Collection<E> exten ...

  3. Java集合(二)--Iterator和Iterable

    Iterable: public interface Iterable<T> { Iterator<T> iterator(); } 上面是Iterable源码,只有一个ite ...

  4. java 集合框架(二)Iterable接口

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  5. java集合迭代器

    一.Java中有一个设计模式是迭代器模式 1.迭代器模式定义迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 2.迭代器模式概述Java集合框 ...

  6. 集合迭代器Iterator

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 什么是迭代器Iterator? Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比 ...

  7. Java 实现迭代器(Iterator)模式

    类图 /** * 自己定义集合接口, 相似java.util.Collection * 用于数据存储 * @author stone * */ public interface ICollection ...

  8. Java 集合、Iterator迭代器、泛型等

    01集合使用的回顾 A:集合使用的回顾 a.ArrayList集合存储5个int类型元素 public static void main(String[] args) { ArrayList<I ...

  9. Java集合、Iterator迭代器和增强for循环整理

    集合 集合,集合是java中提供的一种容器,可以用来存储多个数据. 数组的长度是固定的.集合的长度是可变的.集合中存储的元素必须是引用类型数据 1.1      ArrayList集合存储元素 pac ...

  10. Java中迭代器Iterator的使用

    Java集合类中Map接口下的相关类并没有像Collection接口的相关类一样实现get()方法,因此在要实现遍历输出的场景中没法直接用get()方法来取得对象中的数据,但Java本身提供了另一种遍 ...

随机推荐

  1. HTML Strip Char Filter

    The html_strip character filter strips HTML elements from the text and replaces HTML entities with t ...

  2. Codeforces Round #555 (Div. 3) C2. Increasing Subsequence (hard version)【模拟】

    一 题面 C2. Increasing Subsequence (hard version) 二 分析 需要思考清楚再写的一个题目,不能一看题目就上手,容易写错. 分以下几种情况: 1 左右两端数都小 ...

  3. JavaScript《一》

    脚本语言概念:不需要提前编译的,即时执行的语言,如js,t-sql等 在一个js块中,只要有一个语句出现错误,整个块都不执行 强类型:在编译时就已经确定的类型,弱类型,在运行时,编译器自动根据赋值在确 ...

  4. 部署一个flask服务记录

    最近使用flask写了一些简单的服务. 服务部署到服务器上进行使用,这个过程会有一些问题,需要进行记录一下. 说明运行的环境情况.使用的是python3.6的虚拟环境,系统是centos7,其他的有u ...

  5. Visual Studio 跨平台開發實戰(5) - Xamarin Android 多頁面應用程式開發 (转帖)

    前言 大部份的Android 都具有實體或虛擬的Back鍵. 因此在處理多頁面應用程式時, 與先前所介紹的iOS Navigation controller 比較起來會簡單許多. 1. 開啟Visua ...

  6. 【ORACLE】ID 2299494.1 安装Oracle 11g 86%报错:Error in invoking target 'agent nmhs' of makefile

    参考: ID 2299494.1 In this Document   Symptoms   Changes   Cause   Solution   References APPLIES TO: O ...

  7. dubbo接口快速测试技巧

    在分布式系统的开发中,用到了dubbo+zookeeper技术,最近遇到一个问题,产品上线后,我负责的模块出了问题,某个bean中某个字段的值一直为null,而这个bean是我调用注册在zookeep ...

  8. 虹软linux错误

  9. LightOJ 1214 Large Division

    Large Division Given two integers, a and b, you should check whether a is divisible by b or not. We ...

  10. 入门系列之使用fail2ban防御SSH服务器的暴力破解攻击

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由SQL GM发表于云+社区专栏 介绍 对于SSH服务的常见的攻击就是暴力破解攻击--远程攻击者通过不同的密码来无限次地进行登录尝试.当 ...