详解Iterable接口与Iterator接口异同与使用

标签: Java

保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/61/ )。

Iterable接口与Iterator接口是大家经常接触到的两个接口,它们都代表与迭代操作相关的能力。

Iterator单词的意思是“迭代器”,Iterable单词的意思是“可迭代的”。如果一个类是迭代器,那基于它可以实现迭代操作;而如果一个类能够给出一个迭代自身内元素的迭代器,那它就是可迭代的。

因此,Iterable接口非常简单,主要定义了一个Iterator<T> iterator()抽象方法用以返回一个Iterator对象(在Jdk 1.8中增加了forEach方法和spliterator方法)。

Iterator接口表示一个针对集合的迭代器,Iterator接口定义了迭代器最重要的方法:

在编程开发中,Iterable接口与Iterator接口经常被用到。例如我们常用的for-each就是基于这两个接口实现的。例如下面代码所示的for-each操作:

List<User> userList = new ArrayList<>();
for (User user : userList) {
    System.out.println(user);
}

经过编译后在class文件中变成了如下所示的样子。

List<User> userList = new ArrayList();
Iterator var2 = userList.iterator();

while(var2.hasNext()) {
    User user = (User)var2.next();
    System.out.println(user);
}

这是因为for-each是一个语法糖操作,会由编译器在编译阶段帮我们转化为基本语法。于是我们使用for-each操作对List中的元素进行遍历时,List作为Iterable接口的子类先通过iterator方法给出一个Iterator对象,然后基于Iterator对象实现了List中所有元素的遍历。

语法糖是编程语言中一种简化的语法,它能够使得代码更加简洁。对于Java语言而言,JVM并不识别语法糖中的语句,因此这些语句会在编译阶段被还原成基本的语句。

要想查看一段java代码在class文件中的真实形态,最简单的方法是使用集成开发软件找到target目录下对应的class文件后查看。也可以使用自己使用javac命令编译后使用相关工具打开对应的class文件查看。

最后我们再总结一下,Iterable接口表征一个类是可迭代的,Iterator接口表征一个类是迭代器:

以上内容均参考《通用源码阅读指导书——MyBatis源码详解》一书。

通用源码阅读指导书-京东自营

《通用源码阅读指导书》

阅读源码确实对编程能力的提升有很大的帮助。《通用源码阅读指导书——MyBatis源码详解》是一本以MyBatis的源码为实例讲述源码阅读方法的书籍,并且附带有示例项目源码,MyBatis的全中文注解。书籍还总结了大量的编程知识和架构经验,对提升编程和架构能力十分有用。

而MyBatis中有很多地方用到了Iterable接口与Iterator接口,我们参照《通用源码阅读指导书——MyBatis源码详解》了解下其具体使用。

在使用MyBatis进行数据库查询时,经常会查询到大量的结果。如下面代码所示的例子中,我们查询到了大量的User对象,并使用List接受了这些对象。

List<User> userList = userMapper.queryUserBySchoolName(userParam);

但有些时候,我们希望逐一读入和处理查询结果,而不是一次读入整个结果集。因为前者能够减少对内存的占用,这在处理大量的数据时会显得十分必要。游标就能够帮我们实现这一目的,它支持我们每次从结果集中取出一条结果。

MyBatis中使用游标进行查询非常简单,映射文件不需要任何的变动,只需要在映射接口中标明返回值类型是Cursor即可,如下所示。

Cursor<User> queryUserBySchoolName(User user);

然后便可以用下面的方式来接收和处理结果。

UserMapper userMapper = session.getMapper(UserMapper.class);
User userParam = new User();
userParam.setSchoolName("Sunny School");
Cursor<User> userCursor = userMapper.queryUserBySchoolName(userParam);
for (User user : userCursor) {
    System.out.println("name : " + user.getName() + " ;  email : " + user.getEmail());
}

其最终实现就是使用迭代器Iterator。其涉及的具体的MyBatis源码我们不再展开,大家可以参考《通用源码阅读指导书——MyBatis源码详解》的“第21章 cursor包”章节。


最后,我是高级架构师易哥,这里是架构研究所。真心希望本文能让大家有所收获。

欢迎关注我们,我会偶尔出没分享软件架构编程相关的干货知识。

可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。

作者书籍推荐