Java 集合:迭代器(Iterator, Iterable)
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)的更多相关文章
- Java集合迭代器 Iterator分析
简介 迭代器是遍历容器的一种常用方法,它屏蔽了容器的实现细节,无需暴露数据结构内部,就可以对容器进行遍历,迭代器本身也是一种设计模式,迭代是一种特殊的遍历方式. Iterator 在java中,迭代器 ...
- java集合---迭代器iterator
一:ArraryList 最终继承超级接口Collection,Colection接口继承Iterator接口. public interface Collection<E> exten ...
- Java集合(二)--Iterator和Iterable
Iterable: public interface Iterable<T> { Iterator<T> iterator(); } 上面是Iterable源码,只有一个ite ...
- java 集合框架(二)Iterable接口
Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...
- java集合迭代器
一.Java中有一个设计模式是迭代器模式 1.迭代器模式定义迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 2.迭代器模式概述Java集合框 ...
- 集合迭代器Iterator
迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 什么是迭代器Iterator? Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比 ...
- Java 实现迭代器(Iterator)模式
类图 /** * 自己定义集合接口, 相似java.util.Collection * 用于数据存储 * @author stone * */ public interface ICollection ...
- Java 集合、Iterator迭代器、泛型等
01集合使用的回顾 A:集合使用的回顾 a.ArrayList集合存储5个int类型元素 public static void main(String[] args) { ArrayList<I ...
- Java集合、Iterator迭代器和增强for循环整理
集合 集合,集合是java中提供的一种容器,可以用来存储多个数据. 数组的长度是固定的.集合的长度是可变的.集合中存储的元素必须是引用类型数据 1.1 ArrayList集合存储元素 pac ...
- Java中迭代器Iterator的使用
Java集合类中Map接口下的相关类并没有像Collection接口的相关类一样实现get()方法,因此在要实现遍历输出的场景中没法直接用get()方法来取得对象中的数据,但Java本身提供了另一种遍 ...
随机推荐
- HTML Strip Char Filter
The html_strip character filter strips HTML elements from the text and replaces HTML entities with t ...
- Codeforces Round #555 (Div. 3) C2. Increasing Subsequence (hard version)【模拟】
一 题面 C2. Increasing Subsequence (hard version) 二 分析 需要思考清楚再写的一个题目,不能一看题目就上手,容易写错. 分以下几种情况: 1 左右两端数都小 ...
- JavaScript《一》
脚本语言概念:不需要提前编译的,即时执行的语言,如js,t-sql等 在一个js块中,只要有一个语句出现错误,整个块都不执行 强类型:在编译时就已经确定的类型,弱类型,在运行时,编译器自动根据赋值在确 ...
- 部署一个flask服务记录
最近使用flask写了一些简单的服务. 服务部署到服务器上进行使用,这个过程会有一些问题,需要进行记录一下. 说明运行的环境情况.使用的是python3.6的虚拟环境,系统是centos7,其他的有u ...
- Visual Studio 跨平台開發實戰(5) - Xamarin Android 多頁面應用程式開發 (转帖)
前言 大部份的Android 都具有實體或虛擬的Back鍵. 因此在處理多頁面應用程式時, 與先前所介紹的iOS Navigation controller 比較起來會簡單許多. 1. 開啟Visua ...
- 【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 ...
- dubbo接口快速测试技巧
在分布式系统的开发中,用到了dubbo+zookeeper技术,最近遇到一个问题,产品上线后,我负责的模块出了问题,某个bean中某个字段的值一直为null,而这个bean是我调用注册在zookeep ...
- 虹软linux错误
- LightOJ 1214 Large Division
Large Division Given two integers, a and b, you should check whether a is divisible by b or not. We ...
- 入门系列之使用fail2ban防御SSH服务器的暴力破解攻击
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由SQL GM发表于云+社区专栏 介绍 对于SSH服务的常见的攻击就是暴力破解攻击--远程攻击者通过不同的密码来无限次地进行登录尝试.当 ...