JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序
前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹、车水马龙。
前两篇文章介绍了Collection框架的主要接口和常用类,例如List、Set、Queue,和ArrayList、HashSet、LinkedList等等。根据核心框架图,相信我们都已经对Collection这个JavaSE中最常用API之一有一个较为全面的认识。
这个学习过程,还可以推及到其他常用开源框架和公司项目的学习和熟悉上面。借助开发工具或说明文档,先是对项目整体有一个宏观的认识,再根据这个认识逐一熟悉各个核心模块。(如果对关于Collection的两篇文章感兴趣的话,可以在文章的最末尾点击链接阅读。)
1.5 遍历对象的Iterator
Collection,顾名思义,就是收集,在JavaSE当中起到了收集对象的作用。
收集完对象之后,有一个非常普遍的需求,就是要遍历所收集的对象。学生报名之后,老师有浏览都有哪些学生已经注册的需要;客户下了订单之后, 商家有看看哪些商品被购买的需要;病人挂号之后,医院工作人员有了解门诊工作量的需要。
1.5.1 遍历对象遇到的问题
如果要写一个forEach()方法,可以显示List收集的所有对象,也许你会这么写:
private static void forEach(List list) {
int size = list.size();
for(int i = 0; i < size; i++) {
System.out.println(list.get(i));
}
}
这个方法适用于所有实现List接口的对象,如ArrayList、LinkedList等。如果要让你写个forEach()方法显示Set收集的所有对象,你该怎么写呢?在查看过Set的API说明文档后,发现有个toArray()方法,可以将Set收集的对象转为Object[]返回,所以你会这么写:
private static void forEach(Set set) {
for(Object o : set.toArray()) {
System.out.println(o);
}
}
这个方法适用于所有操作Set接口的对象,如HashSet、TreeSet等。如果现在要让你再写一个forEach()方法,可以显示Queue收集的对象,也许你会这么写:
private static void forEach(Queue queue) {
while(queue.peek() != null) {
System.out.println(queue.poll());
}
}
表面上看来好像是正确的,不过Queue的poll()方法会取出对象,当你显示完Queue中所有对象,Queue也空了。这并不是我们想要的结果,怎么办呢?
1.5.2 使用Iterator
事实上,无论是List、Set还是Queue,都会有个Queue,都会有个iterator()方法,这个方法在JDK1.4之前,是定义在Collection接口中,而它们都继承自Collection,所以也都拥有iterator()的行为。
iterator()方法会返回java.util.Iterator接口的操作对象,这个对象包括了Collection收集的所有对象,你可以使用Iterator的hasNext()看看有无下一个对象,若有的话,再使用next()取得下一个对象。因此,无论List、Set、Queue还是任何Collection,都可以使用以下的forEach()方法来显示所收集的对象:
private static void forEach(Collection collection) {
Iterator iterator = collection.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
在JDK5之后,原先定义在Collection中的iterator()方法,提升至新的java.util.Iterable父接口,因此在JDK5之后,可以使用以下forEach()方法显示收集的所有对象:
private static void forEach(Iterable iterable) {
Iterator iterator = iterable.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
接下来,我们可以写一个比较完整的demo,看看是否能正确使用forEach()方法:
import java.util.*; /**
* Iterator实验用例
*/
public class ForEach {
private static void forEach(Iterable iterable) {
Iterator iterator = iterable.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
} public static void main(String[] args) {
List list = Arrays.asList("Tim", "Jack", "Jane");
forEach(list);
forEach(new HashSet(list));
forEach(new ArrayDeque(list));
}
}
运行之后,我们可以得到以下结果:
1.5.3 Iterator小结
遍历显示所收集的所有对象,这是使用Celletion框架时频繁会遇到的需求。在了解List、Set、Queue如何显示收集对象之后,我们意外地发现可以通过使用定义在上层接口的iterator()方法,达到正确、安全地满足这一需求的目的。
无论是学习Colletion等JavaSE的API框架,还是熟悉开源或公司项目,在熟悉各个模块的同时,也要有抽象的理解能力来宏观地理解项目。在满足一些普遍常用需求时,可以找到更通用、复用程度更高的解决方案。如果能做到这一点,就不会犯新手常犯的“只见树木不见森林”的错误。
1.6 收集对象后的排序
在收集对象之后,对对象进行排序是常用的动作。
我的上家是做ERP系统的,常常有这样的需求:几家供应商提供的报价单价格不一样,系统用户希望可以在按照报价从低到高查看商品的报价;生产物料紧缺时,他们希望根据物料需求日期从近到远查看;同一个生产件,不同的生产配方和工艺流程产生的生产成本是不一样的,他们希望能按照成本从低到高查看生产明细。以上的这些需求,都要求系统对所收集的不同对象进行排序
1.6.1 Collection自带的排序算法
java.util.Collections提供有sort()方法,用来满足对对象进行排序的需求。由于必须有索引才能进行排序,因此Collections的sort()方法接受List实现对象。例如以下这段demo:
import java.util.*; /**
* Collections的sort()方法实验用例
*/
public class Sort {
public static void main(String[] args) {
List numbers = Arrays.asList(10, 3, 4, 21, 9);
Collections.sort(numbers);
System.out.println(numbers);
}
}
执行结果我们可以看到已经排好序的一串数字:
可是,如果我们需要排序的对象稍微复杂一点点,会出现什么样的情况呢?
import java.util.*; /**
* Collections的sort()方法实验用例2
*/
class Account {
private String name;
private int balance; Account (String name, int balance) {
this.name = name;
this.balance = balance;
} @Override
public String toString() {
return String.format("Account(%s, %d)", name, balance);
}
} public class Sort {
public static void main(String[] args) {
List accounts = Arrays.asList(
new Account("Tim", 100),
new Account("Tom", 1300),
new Account("Jack", 5)
);
Collections.sort(accounts);
System.out.println(accounts);
}
}
运行结果出现了抛出ClassCastException报错,到底是怎么回事呢?
1.6.2 实现Comparable
要说原因,是因为你根本没告诉Collections的sort()方法,到底要根据Account的name还是balance进行排序。用一句时下流行的话说:“我有什么办法,我也很绝望啊。”
Collections的sort()方法要求被排序的对象必须实现java.lang.Comparable接口,这个接口有个compareTo()方法必须返回大于0、等于0或小于0的数。这有什么用呢?我们直接来看下面这个针对账户余额排序的demo就了解了:
import java.util.*; /**
* Collections的sort()方法实验用例3
*/
class Account implements Comparable{
private String name;
private int balance; Account (String name, int balance) {
this.name = name;
this.balance = balance;
} @Override
public String toString() {
return String.format("Account(%s, %d)", name, balance);
} @Override
public int compareTo(Object o) {
Account other = (Account) o;
return this.balance - other.balance;
}
} public class Sort {
public static void main(String[] args) {
List accounts = Arrays.asList(
new Account("Tim", 100),
new Account("Tom", 1300),
new Account("Jack", 5)
);
Collections.sort(accounts);
System.out.println(accounts);
}
}
Collections的sort()方法在取得a对象与b对象进行比较时,会先将对象Cast为Comparable(也因为这样,如果对象没实现这个接口,就会抛出ClassCastException),然后调用a.compareTo(b),如果a对象顺序上小于b对象,必须返回小于0的值;如果顺序上相等则返回0;如果顺序上a大于b,则要返回大于0的值。因此,上面的demo输出结果会是按照余额从小到大排列:
1.6.3 实现Comparator
如果你有用过Collections对所收集的String对象排序,你应该会知道JavaSE是按照A、B、C的字母表来排序的。可是,如果今天突然有个需求,要让排序结果反过来呢?
首先,String已经实现了Comparable接口,我们很难进行修改。另外,由于String声明为final,我们也没有办法通过继承的方式重新定义compareTo()方法。不过幸好,JavaSE给这种情况留下了备用的解决方案。
Collections的sort()方法有另一个重载版本,可以接受java.util.Comparator接口的操作对象。如果使用这个版本,排序方式将根据Comparator的compare()方法的定义来决定。例如下面这个demo:
import java.util.*; /**
* Collections的sort()方法实验用例4
*/
class StringComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
String str1 = (String) o1;
String str2 = (String) o2;
return -str1.compareTo(str2);
}
} public class Sort {
public static void main(String[] args) {
List words = Arrays.asList("B", "C", "A", "X", "Z", "Y");
Collections.sort(words, new StringComparator());
System.out.println(words);
}
}
结果如下,符合我们之前的期望:
1.6.4 Sort()小结
在Java的规范中,与顺序有关的行为,通常要不就是对象本身是Comparable,即实现了Comparable接口,要不就是另行制定Comparator对象告知如何排序。
这就是深入学习API的好处,可以介绍遇到麻烦的次数。另外,无论你的工作语言是Java还是PHP、C#,熟悉语言规范是必不可少的内功,是衡量一个程序员实力的硬指标。
相关文章推荐:
JavaSE中Collection集合框架学习笔记(1)——具有索引的List
JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue
如果你喜欢我的文章,可以扫描关注我的个人公众号“李文业的思考笔记”。
不定期地会推送我的原创思考文章。
JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序的更多相关文章
- JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue
前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...
- JavaSE中Collection集合框架学习笔记(1)——具有索引的List
前言:因为最近要重新找工作,Collection(集合)是面试中出现频率非常高的基础考察点,所以好好恶补了一番. 复习过程中深感之前的学习不系统,而且不能再像刚毕业那样死背面试题,例如:String是 ...
- Java集合框架学习笔记
集合类的由来:对象用于封装特有数据,对象多了需要存储,如果对象的长度不确定,就使用集合存储. 集合特点1.用于存储对象的容器.2.集合的长度可变.3.集合中不可以存储基本类型 集合容器因为内部的数据结 ...
- 集合框架学习笔记<二>
1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和ILis ...
- 集合框架学习笔记<三>
一些重要的区别 set与list的区别: set是无索引的,list是有索引的: ArrayList与LinkList的区别: 前者是基于数组实现的,后者是基于链表实现的: 两者的使用方法一样,但是在 ...
- hibernate框架学习笔记4:主键生成策略、对象状态
创建一个实体类: package domain; public class Customer { private Long cust_id; private String cust_name; pri ...
- JavaSE中Map框架学习笔记
前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...
- JavaSE中线程与并行API框架学习笔记1——线程是什么?
前言:虽然工作了三年,但是几乎没有使用到多线程之类的内容.这其实是工作与学习的矛盾.我们在公司上班,很多时候都只是在处理业务代码,很少接触底层技术. 可是你不可能一辈子都写业务代码,而且跳槽之后新单位 ...
- JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?
前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事 ...
随机推荐
- 侯捷STL学习(一)
开始跟着<STL源码剖析>的作者侯捷真人视频,学习STL,了解STL背后的真实故事! 视频链接:侯捷STL 还有很大其他视频需要的留言 第一节:STL版本和重要资源 STL和标准库的区别 ...
- SQL注入攻击[详解]
SQL注入攻击是黑客对数据库进行攻击的常用手段之一.随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多.但是由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候, ...
- js实现防盗图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 乐视开放平台技术架构-servlet和spring mvc篇
在乐视风口浪尖的时候,敢于站出来说我是乐视的而不怕被打脸的,也就是我了.就算我以后不在乐视了,提起来在乐视工作过,我也还是挺骄傲的.因为这是一个有理想,敢拼敢干的公司.想起复仇者联盟里Fury指挥官的 ...
- JS闭包,以及适用场景
闭包的定义 不用解释了,网上到处都是.简单的说:一个定义在函数内部的函数与包含它的外部函数构成了闭包,内部函数可以访问外部函数的变量,这些变量将一直保存在内存中,直到无法再引用这个内部函数 举个例子: ...
- [附录]Discuz X2.5 模板目录结构注释说明
/template/default/common 公共模板目录全局加载 block_forumtree.htm DIY论坛树形列表模块 block_thread.htm DIY帖子模块调用文件 ...
- ubuntu下配置Apache+mod_wsgi+Django项目(个人测试)
经过了一个星期的摸索,查找资料以及实验,我搭建的环境基本能用(还有就是Django后台的静态文件加载的问题) 这里面只是介绍一下我的过程,因为对应Apache还不是很熟练,特别是配置文件.只能供大家参 ...
- 删除iPhone图片,提示“没有删除此项目的权限”
解决方法:设置-照片与相机-iCloud照片图库-关闭 (IOS10)
- 原生javascript 制作canvas 验证码
<canvas id="></canvas> <a href="#" id="changeImg">看不清,换一张 ...
- root权限下找不到 /root/.ssh目录
Xshell配置ssh登陆远程服务器,找不到 root/.ssh目录,报错信息如下: root@ubuntu:/home/xinxin# cd /root/.ssh/bash: cd: /root/. ...