java的iterator_Java集合迭代器 Iterator分析

简介

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

Iterator

在java中,迭代器接口Iterator定义了三种方法

public interface Iterator{//是否还有元素可以迭代,如果有 返回true 没有返回false

boolean hasNext();//返回迭代的下一个元素

E next();//从迭代器指向的 collection 中移除迭代器返回的最后一个元素

voidremove();

}

remove方法是移除迭代器返回的最后一个元素,因此如果没有调用过next方法,直接调用remove方法是错误的做法,并且每执行一次next方法,只能调用一次remove方法

遍历collection时,

(1)先调用Collection子类中的iterator()方法创建迭代器对象,

(2)并用hasNext()方法判断,

(3)如果仍有元素可迭代,再调用next()方法,返回迭代的下一个元素,依次循环直到最后一个元素。如下:

public classIteratorTest {public static voidmain(String[] args) {//创建ArrayList对象

ArrayList arrList = new ArrayList<>();//添加元素

arrList.add("Iterator");

arrList.add("迭代器");

arrList.add("遍历");//用Iterator遍历

Iterator itr = arrList.iterator();//创建迭代器while(itr.hasNext()){//判断是否有元素可迭代

System.out.println(itr.next());//获取迭代元素

}/*或者用for循环

for(Iterator itr1 = arrList.iterator();itr1.hasNext();){

System.out.println(itr1.next());

}*/}

}

java 中遍历取值异常(Hashtable Enumerator)解决办法

用迭代器取值时抛出的异常:java.util.NoSuchElementException: Hashtable Enumerator ,比如下面代码:

//使用迭代器遍历

Iterator it =tableProper.stringPropertyNames().iterator();

sqlMap= new HashMap();while(it.hasNext()){

sqlMap.put(it.next(), tableProper.getProperty(it.next()));

}

这是一个枚举异常,是因为在还没来得及执行it.next()时就开始引用它。我们可以用如下方式解决此问题:

//使用迭代器遍历

Iterator it =tableProper.stringPropertyNames().iterator();

sqlMap= new HashMap();

String key;while(it.hasNext()){

key=it.next();

sqlMap.put(key, tableProper.getProperty(key));

}

所以一般注意:迭代器循环里面只能有一个 it.next(),否则就会报java.util.NoSuchElementException的错误;

另外注意,如果迭代器里面只有一条数据,那么it.next()也会报java.util.NoSuchElementException的错误 ,解决办法就是采用增强for each循环(需要事先知道集合内部类型),比如下面项目中遇到的:

if(device.getDeviceInfos()!=null){for(DeviceInfo h:device.getDeviceInfos()){

device.setSafeLevel(h.getSafeLevel());

device.setLastActiveTime(h.getLastActiveTime());

}

}

device.getDeviceInfos()为一个set集合,里面只会有一条数据,device.getDeviceInfos().get不到里面safeLevel等,使用iterator因为只有一个,it.next()会报NoSuchElementException错误,所以才有foreach遍历比较好。

Iterable

Iterable只有一个iterator方法,该方法会返回一个迭代器,一般情况下使用迭代器的类都会实现Iterable接口而非直接实现Iterator接口

public interface Iterable{//返回一个在一组 T 类型的元素上进行迭代的迭代器。

Iteratoriterator();

}

foreach 就是对迭代器的另外一种使用方式,只要是实现Iterable接口的类,就可以用foreach对自身进行遍历

map 迭代

map接口并未继承Iterable接口,因此本身并不能直接使用迭代器,不过可以转化为collection然后进行迭代,例如:

Map map = new HashMap<>();

map.put("韦德", "35");

Iterator> iterator = map.entrySet().iterator();while(iterator.hasNext()) {

Entry entry =iterator.next();

System.out.println(entry.getKey() + ":" +entry.getValue());

}

map的遍历方式可参考总结的这篇博客:java中遍历Map几种方法

collection 迭代

collection接口继承了Iterable接口,因此只要是collection实例,都可以使用迭代器进行遍历

Collection collection = Arrays.asList("java", "c", "js");

Iterator iterator =collection.iterator();while(iterator.hasNext()) {

String str=iterator.next();

System.out.println(str);

}

用迭代器遍历collection的优势在于遍历的过程中可以remove元素,用foreach则不行

ListIterator

ListIterator是对Iterator的扩展,针对定义了ListIterator方法的有序的容器,可以采用ListIterator进行迭代,ListIterator新增了一些方法,可以在遍历时获取数据的索引,或者逆序遍历等。

public interface ListIterator1 extends Iterator{//是否还有上一个元素 一般逆序遍历时使用

boolean hasPrevious();//返回列表中的上一个元素

E previous();//返回对 next 的后续调用所返回元素的索引。(如果列表迭代器在列表的结尾,则返回列表的大小)

intnextIndex();//返回对 previous 的后续调用所返回元素的索引。(如果列表迭代器在列表的开始,则返回 -1)

intpreviousIndex();//用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。只有在最后一次调用 next 或 previous//后既没有调用 ListIterator.remove 也没有调用 ListIterator.add 时才可以进行该调用。

void set(E e);//将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面(如果有)//或者 previous 返回的下一个元素之后(如果有);

voidadd(E e);//... Iterator methods

}

List提供了两个重载的listIterator方法,可以通过这两个方法拿到一个ListIterator对象

public interface List1 extends Collection{//此列表元素的列表迭代器

ListIteratorlistIterator();//此列表元素的列表迭代器 可以指定一个参数index//index 从列表迭代器返回的第一个元素的索引(通过调用 next 方法)

ListIterator listIterator(intindex);//List other methods

}

使用listIterator对List进行逆序遍历

List list = Arrays.asList("java", "c", "js");

ListIterator listIterator = list.listIterator(list.size());while(listIterator.hasPrevious()) {

System.out.println("前一个元素索引为:" +listIterator.previousIndex());

System.out.println("前一个元素为:" +listIterator.previous());

}

光标(cursor)

迭代器没有当前元素的概念,但有光标(cursor)的概念,如果不指定光标的位置,光标默认在第一个元素之前,此时如果调用next方法,光标会跳到第一个元素和第二个元素中间,并且返回第一个元素

ListIterator listIterator = list.listIterator(list.size());

以上代码,指定了光标的位置,在最后一个元素的后面,此次要调用next方法会抛异常,因为没有下一个元素,如果调用nextIndex则会返回容器长度,调用previous则返回最后一个元素,同时光标向上移动一位。

总结

迭代器在使用的过程中其实还有诸多限制,如果使用不当,很可能出现死循环,抛异常等问题,例如:如果在用ListIterator逆序遍历的时候新增,会造成死循环。

因此在学习迭代器的时候,不仅要掌握其使用方法,还要明白其实现原理。看源码是不错的学习办法,有兴趣的可以看看Collection的众多实现类对迭代的实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值