最近在用这本书学习基本句法往上高级一些的Java知识:Data Structures in Java: From Abstract Data Types to the Java Collections Framework (by Simon Gray,第二版,书中案例大约是Java5/6),一开始作者对Java的框架、软件开发思路等方面作了系统而简明的介绍,随后用多边形和多面体的案例讲解了OOP、Generic Types和软件测试的知识。
注: 在进入A Basic Collection Class部分后,由于原书的在线补充资料无法获取,一些代码和练习只能根据书上的内容脑补并自行尝试;Basic Collection部分的第一个案例就是这个情况,由于缺少作者提供的一个package,源代码中的Collection的类型根据实际内容被我定义成ArrayList(见附件)。原书的BasicCollection<String>()类型我推测可能是前面讲的linked list,但如何放在package在被直接调用成无parameter的constructor还不清楚。
这个案例通过建立一个简单的以String为类型的Collection,示范对其中元素的操作,比如添加(add)、输出、删除(remove),其中输出和删除通过Iterator进行批量操作。
Java lang 里面有一个Interface叫Iterable<T>,Java Collection Framework里有一个Interface 叫 Iterable<T>,根据[1][2][3][4]等加上自己的理解,Collection是自动implement Iterable的,而进行iteration所使用的iterator()这个方法在Iterable里调用,产生的结果是instantiate一个Iterator的object,这样对这个object就可以进行各种操作达到我们的目的。
案例代码中,先对Collection加入3个String(都是电影名字),然后用Iterator的Object输出3个电影名,除了for (initialization; testExpression; update)这种三合大神方式之外,案例给出了一个新的for句法:
【3种句法之1st】
Iterator<String> iter;
for (iter = movies.iterator(); iter.hasNext(); )
System.out.println(" " + iter.next());
这种句法被称为For-Each loop,也被称为Enchanced For, 是Java 5开始增加的。[5] 用两个参数,前一个是进行iteration的object,后一个是method持续的判断条件,注意两个参数后面都有分号。在这里hasNext() 让"cursor"从collection的第一个元素开始进行到最后一个,于是3个电影名字都输出了出来。
【3种句法之2nd】
在后面对处理过的(另一个)object进行输出操作时,案例给出了另一种句法:
for (String movie : movies)
System.out.println(" " + movie);
句法结构是: for(data_type item : collection) [6],先声明数据类型(这里是String)和名称,然后冒号(读作”in“)加上collection,这样让collection里面元素都进入给定数据类型所创建的实例中了(尚不清楚data_type和collection的<Type>能否不同,比如int变成String,留待接下来学习中关注)
【3种句法之3rd】
第三种是我试着用while写了一下,发现也很简明且正确运行:
Iterator<String> iter=movies.iterator();
while( iter.hasNext())
System.out.println(" " + iter.next());
这个是对第1个的变形,把Iterator声明和实例创建全部移到了while的前面。
【有趣的错误】
下面展示一个在对第1种句法变形过程中出现的一个错误例子
for (movies.iterator(); movies.iterator().hasNext(); )
System.out.println(" " + movies.iterator().next());
最初这么改的缘由是看看不做声明(Iterator<String> iter)在直接让collection (movies)加上.iterator() 实例化会怎么样。
先看正确情况下运行结果
再看改成上面代码错误运行结果
collection的第1项被无限重复输出(行数过多,秒按了停止键才使窗口保留了最开始"Titles..."以确认循环前的部分是正确运行的)
我对此的猜测是:由于没有预先声明成一个具体而唯一的实例,每一次循环中,movies.iterator()都重新建立了一个临时的实例,这样cursor永远在第一位而无法向前推进,输出的也就总是第一项了。
【总结和反思】
数据类型集中体现了abstraction和OOP的原理,generic type和Collection Framework是数据结构初学课程中在比较新的内容。这个教材从abstract data type和OOP的思路切入并贯穿始终,是一种主干集中的讲述方式,然而在初解generic type时过于抽象,所举例子不能运行而且与后面例子不衔接,不过由于这些核心思想和主干知识会在后续反复出现并巩固加深理解,目前进展不失为好的开头。
ps:java文件里有一些个人学习目的而加入的注释,仅供参考,欢迎指正
[1] https://stackoverflow.com/questions/6863182/what-is-the-difference-between-iterator-and-iterable-and-how-to-use-them
[2] https://www.techiedelight.com/differences-between-iterator-and-iterable-in-java/
[3] https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html
[4] https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html
[5] https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html
[6] https://www.programiz.com/java-programming/enhanced-for-loop