java迭代器原理_Java迭代器原理

1迭代器模式

迭代器是一种设计模式,这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。

一般实现方式如下:(来自)

9kA

public interfaceIterator {public booleanhasNext();publicObject next();

}

public interfaceContainer {publicIterator getIterator();

}

public class NameRepository implementsContainer {public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

@OverridepublicIterator getIterator() {return newNameIterator();

}private class NameIterator implementsIterator {intindex;

@Overridepublic booleanhasNext() {if(index

}return false;

}

@OverridepublicObject next() {if(this.hasNext()){return names[index++];

}return null;

}

}

}

public classIteratorPatternDemo {public static voidmain(String[] args) {

NameRepository namesRepository= newNameRepository();for(Iterator iter =namesRepository.getIterator(); iter.hasNext();){

String name=(String)iter.next();

System.out.println("Name : " +name);

}

}

}

一般情况,我们自己开发时很少自定义迭代器,因为java本身已经把迭代器做到内部中了

2Java中的迭代器

(1)Iterator接口

packagejava.util;importjava.util.function.Consumer;public interface Iterator{/*** 如果迭代器又更多的元素,返回true。*换句话说,如果next方法返回一个元素而不是抛出一个异常,则返回true。

*/

booleanhasNext();//返回迭代器中的下一个元素,如果没有,则抛出NoSuchElementException异常

E next();/*** 从底层集合中删除该迭代器返回的最后一个元素(可选操作)。每执行一次next方法这个方法只能被调用1次。

*如果在迭代过程中,除了调用此方法之外,任何其他方法修改基础集合,则迭代器的行为是不确定的。*默认实现是抛出一个UnsupportedOperationException异常,不执行其他操作。*如果每次调用该方法前next方法没有执行,则抛出IllegalStateException异常。

*/

default voidremove() {throw new UnsupportedOperationException("remove");

}/**

*@since1.8(函数编程)。*对每个剩余元素执行给定的操作,直到所有元素都被处理或动作抛出异常为止。*如果指定了该顺序,则按迭代顺序执行操作。动作抛出的异常被传递给调用者。*如果action为null,则抛出NullPointerException

*/

default void forEachRemaining(Consumer super E>action) {

Objects.requireNonNull(action);while(hasNext())

action.accept(next());

}

}

首先,Iterator接口是属于java.util包的。然后里面只有4个方法(用法介绍请看注释)。

forEachRemaining方法是Java8函数编程新加入的。作用是对前游标之后的每个元素进行处理(没有返回值),具体怎么处理根据传入的函数。这项里操作使得迭代器更加灵活,操作粒度更加细致。

补充:default关键字可以让接口中的方法可以有默认的函数体,当一个类实现这个接口时,可以不用去实现这个方法,当然,这个类若实现这个方法,就等于子类覆盖了这个方法,最终运行结果符合Java多态特性。(Java8的新特性)

类注释:

/*** An iterator over a collection. {@codeIterator} takes the place of {@linkEnumeration} in the Java Collections Framework. Iterators

* differ from enumerations in two ways:

*

*

*

Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.

*

Method names have been improved.

*

*

*

This interface is a member of the Java Collections Framework.*/

Iterator是集合上的迭代器。在Java集合框架中Iterator用来替代Enumeration,Iterator与Enumeration有以下两点区别:

Iterator允许调用者通过定于语义良好的迭代器删除底层集合中的元素。

方法名称已得到改进。

这个接口是Java集合框架的成员。除了如上两点不同外,Java8版本Iterator还加入了函数式编程。

(2)Iterable接口

packagejava.lang;// 实现此接口,允许对象成为“for-each loop”语句的目标。

public interface Iterable{// 返回类型为 T元素的迭代器。Iteratoriterator();/***@since1.8

* 对Iterable的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。

* 除非实现类另有规定,否则按照迭代的顺序执行操作(如果指定了迭代顺序)。 动作抛出的异常被转发给调用者。

* 抛出*/

default void forEach(Consumer super T>action) {

Objects.requireNonNull(action);for (T t : this) {

action.accept(t);

}

}/***@since1.8

* 在Iterable描述的元素上创建一个Spliterator。Spliterator继承了迭代器的fail-fast属性。

**/

default Spliteratorspliterator() {return Spliterators.spliteratorUnknownSize(iterator(), 0);

}

}

Java集合包最常用的有Collection和Map两个接口的实现类。Map的实现类迭代器是内部实现的,而Collection继承了Iterable接口。

这里以ArrayList为例,梳理一下Iterator的工作流程。

ArrayList是Collection的子类,而Collection又实现了Iterable接口,Iterable接口里面有iterator()方法(该方法返回一个迭代器对象)。所以,ArrayList(或其父类)也必须实现iterator()方法。

iterator()方法返回一个Iterator对象,而前文中Iterator是个接口。我们不能不知道具体用哪个实现类也不能直接new接口,所以我们找到其直接父类AbstractList,查看iterator()到底如何实现的:

public Iteratoriterator() {return newItr();

}private class Itr implements Iterator{// 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 booleanhasNext() {return cursor !=size();

}publicE next() {

checkForComodification();try{int i =cursor;

E next=get(i);

lastRet=i;

cursor= i + 1;returnnext;

}catch(IndexOutOfBoundsException e) {

checkForComodification();throw newNoSuchElementException();

}

}public voidremove() {if (lastRet < 0)throw newIllegalStateException();

checkForComodification();try{

AbstractList.this.remove(lastRet);if (lastRet

cursor--;

lastRet= -1;

expectedModCount=modCount;

}catch(IndexOutOfBoundsException e) {throw newConcurrentModificationException();

}

}final voidcheckForComodification() {if (modCount !=expectedModCount)throw newConcurrentModificationException();

}

}

这里是通过内部类实现了Iterator接口,然后再将其实例对象返回。

原理很简单,每调用一次next方法,先返回当前游标指向位置的值,然后游标往下移动一位,直到游标数值等于list的size。

而在ArrayList类里面又提供了一个实现版本:

/*** An optimized version of AbstractList.Itr*/

private class Itr implements Iterator{int cursor; //index of next element to return

int lastRet = -1; //index of last element returned; -1 if no such

int expectedModCount =modCount;

Itr() {}public booleanhasNext() {return cursor !=size;

}

@SuppressWarnings("unchecked")publicE next() {

checkForComodification();int i =cursor;if (i >=size)throw newNoSuchElementException();

Object[] elementData= ArrayList.this.elementData;if (i >=elementData.length)throw newConcurrentModificationException();

cursor= i + 1;return (E) elementData[lastRet =i];

}public voidremove() {if (lastRet < 0)throw newIllegalStateException();

checkForComodification();try{

ArrayList.this.remove(lastRet);

cursor=lastRet;

lastRet= -1;

expectedModCount=modCount;

}catch(IndexOutOfBoundsException ex) {throw newConcurrentModificationException();

}

}

@Override

@SuppressWarnings("unchecked")public void forEachRemaining(Consumer super E>consumer) {

Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i =cursor;if (i >=size) {return;

}final Object[] elementData = ArrayList.this.elementData;if (i >=elementData.length) {throw newConcurrentModificationException();

}while (i != size && modCount ==expectedModCount) {

consumer.accept((E) elementData[i++]);

}//update once at end of iteration to reduce heap write traffic

cursor =i;

lastRet= i - 1;

checkForComodification();

}final voidcheckForComodification() {if (modCount !=expectedModCount)throw newConcurrentModificationException();

}

}

next方法很好理解,和父类大概是一个意思。remove方法是调用ArrayList.this.remove(lastRet)实现:

public E remove(intindex) {

rangeCheck(index);

modCount++;

E oldValue=elementData(index);int numMoved = size - index - 1;if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null; //clear to let GC do its work

returnoldValue;

}

numMoved 是计算要移动的元素个数(删除数组的某一位置的值,后面的值要依次往前移)。

cursor =lastRet;

lastRet = -1;

表示删除之后,游标前移1位。为什么这么做?举个例子,数组a = [1,2,3,4],若cursor = 2,游标指向数字3,则lastRet = 1。当删除a[1]的时候,a = [1,3,4]。3对应的位置变为1了,所以会有cursor =lastRet。

lastRet的值置为-1,这里很好的解释了前面注释中为什么remove方法一定要在next方法之后执行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值