Java Collections API 您不知道的 5 件事Word下载.docx
- 文档编号:6799874
- 上传时间:2023-05-07
- 格式:DOCX
- 页数:26
- 大小:26.14KB
Java Collections API 您不知道的 5 件事Word下载.docx
《Java Collections API 您不知道的 5 件事Word下载.docx》由会员分享,可在线阅读,更多相关《Java Collections API 您不知道的 5 件事Word下载.docx(26页珍藏版)》请在冰点文库上搜索。
System.out.println(argList);
}
}
注意,返回的
List
是不可修改的,所以如果尝试向其中添加新元素将抛出一个
UnsupportedOperationException。
而且,由于
Arrays.asList()
使用
varargs
参数表示添加到
的元素,所以还可以使用它轻松地用以
new
新建的对象创建
2.迭代的效率较低
将一个集合(特别是由数组转化而成的集合)的内容转移到另一个集合,或者从一个较大对象集合中移除一个较小对象集合,这些事情并不鲜见。
您也许很想对集合进行迭代,然后添加元素或移除找到的元素,但是不要这样做。
在此情况下,迭代有很大的缺点:
∙每次添加或移除元素后重新调整集合将非常低效。
∙每次在获取锁、执行操作和释放锁的过程中,都存在潜在的并发困境。
∙当添加或移除元素时,存取集合的其他线程会引起竞争条件。
可以通过使用
addAll
或
removeAll,传入包含要对其添加或移除元素的集合作为参数,来避免所有这些问题。
3.用for循环遍历任何Iterable
Java5中加入Java语言的最大的便利功能之一,增强的for循环,消除了使用Java集合的最后一道障碍。
以前,开发人员必须手动获得一个
Iterator,使用
next()
获得
Iterator
指向的对象,并通过
hasNext()
检查是否还有更多可用对象。
从Java5开始,我们可以随意使用for循环的变种,它可以在幕后处理上述所有工作。
实际上,这个增强适用于实现
Iterable
接口的任何对象,而不仅仅是
Collections。
清单2显示通过
提供
Person
对象的孩子列表的一种方法。
这里不是提供内部
的一个引用(这使
外的调用者可以为家庭增加孩子—而大多数父母并不希望如此),Person
类型实现
Iterable。
这种方法还使得for循环可以遍历所有孩子。
清单2.增强的for循环:
显示孩子
//Person.java
publicclassPerson
implementsIterable<
Person>
publicPerson(Stringfn,Stringln,inta,Person...kids)
this.firstName=fn;
this.lastName=ln;
this.age=a;
for(Personchild:
kids)
children.add(child);
publicStringgetFirstName(){returnthis.firstName;
publicStringgetLastName(){returnthis.lastName;
publicintgetAge(){returnthis.age;
publicIterator<
iterator(){returnchildren.iterator();
publicvoidsetFirstName(Stringvalue){this.firstName=value;
publicvoidsetLastName(Stringvalue){this.lastName=value;
publicvoidsetAge(intvalue){this.age=value;
publicStringtoString(){
return"
[Person:
"
+
firstName="
+firstName+"
lastName="
+lastName+"
age="
+age+"
]"
;
privateStringfirstName;
privateStringlastName;
privateintage;
privateList<
children=newArrayList<
();
//App.java
publicclassApp
Personted=newPerson("
Ted"
"
Neward"
39,
newPerson("
Michael"
16),
Matthew"
10));
//Iterateoverthekids
for(Personkid:
ted)
System.out.println(kid.getFirstName());
在域建模的时候,使用
有一些明显的缺陷,因为通过
iterator()
方法只能那么“隐晦”地支持一个那样的对象集合。
但是,如果孩子集合比较明显,Iterable
可以使针对域类型的编程更容易,更直观。
4.经典算法和定制算法
您是否曾想过以倒序遍历一个
Collection?
对于这种情况,使用经典的JavaCollections算法非常方便。
在上面的
清单2
中,Person
的孩子是按照传入的顺序排列的;
但是,现在要以相反的顺序列出他们。
虽然可以编写另一个for循环,按相反顺序将每个对象插入到一个新的
ArrayList
中,但是3、4次重复这样做之后,就会觉得很麻烦。
在此情况下,清单3中的算法就有了用武之地:
清单3.ReverseIterator
publicclassReverseIterator
//MakeacopyoftheList
kids=newArrayList<
(ted.getChildren());
//Reverseit
Collections.reverse(kids);
//Displayit
System.out.println(kids);
Collections
类有很多这样的“算法”,它们被实现为静态方法,以
作为参数,提供独立于实现的针对整个集合的行为。
而且,由于很棒的API设计,我们不必完全受限于
类中提供的算法—例如,我喜欢不直接修改(传入的Collection的)内容的方法。
所以,可以编写定制算法是一件很棒的事情,例如清单4就是一个这样的例子:
清单4.ReverseIterator使事情更简单
classMyCollections
publicstatic<
T>
reverse(List<
src)
results=newArrayList<
(src);
Collections.reverse(results);
returnresults;
5.扩展CollectionsAPI
以上定制算法阐释了关于JavaCollectionsAPI的一个最终观点:
它总是适合加以扩展和修改,以满足开发人员的特定目的。
例如,假设您需要
类中的孩子总是按年龄排序。
虽然可以编写代码一遍又一遍地对孩子排序(也许是使用
Collections.sort方法),但是通过一个
Collection
类来自动排序要好得多。
实际上,您甚至可能不关心是否每次按固定的顺序将对象插入到
中(这正是
的基本原理)。
您可能只是想让它们按一定的顺序排列。
java.util
中没有
类能满足这些需求,但是编写一个这样的类很简单。
只需创建一个接口,用它描述
应该提供的抽象行为。
对于
SortedCollection,它的作用完全是行为方面的。
清单5.SortedCollection
publicinterfaceSortedCollection<
E>
extendsCollection<
publicComparator<
getComparator();
publicvoidsetComparator(Comparator<
comp);
编写这个新接口的实现简直不值一提:
清单6.ArraySortedCollection
publicclassArraySortedCollection<
implementsSortedCollection<
Iterable<
privateComparator<
comparator;
privateArrayList<
list;
publicArraySortedCollection(Comparator<
c)
this.list=newArrayList<
parator=c;
publicArraySortedCollection(Collection<
?
extendsE>
src,Comparator<
sortThis();
getComparator(){returncomparator;
cmp){comparator=cmp;
publicbooleanadd(Ee)
{booleanr=list.add(e);
returnr;
publicbooleanaddAll(Collection<
ec)
{booleanr=list.addAll(ec);
publicbooleanremove(Objecto)
{booleanr=list.remove(o);
publicbooleanremoveAll(Collection<
>
{booleanr=list.removeAll(c);
publicbooleanretainAll(Collection<
ec)
{booleanr=list.retainAll(ec);
publicvoidclear(){list.clear();
publicbooleancontains(Objecto){returnlist.contains(o);
publicbooleancontainsAll(Collection<
c){returnlist.containsAll(c);
publicbooleanisEmpty(){returnlist.isEmpty();
iterator(){returnlist.iterator();
publicintsize(){returnlist.size();
publicObject[]toArray(){returnlist.toArray();
public<
T[]toArray(T[]a){returnlist.toArray(a);
publicbooleanequals(Objecto)
if(o==this)
returntrue;
if(oinstanceofArraySortedCollection)
ArraySortedCollection<
rhs=(ArraySortedCollection<
)o;
returnthis.list.equals(rhs.list);
returnfalse;
publicinthashCode()
returnlist.hashCode();
publicStringtoString()
returnlist.toString();
privatevoidsortThis()
Collections.sort(list,comparator);
这个实现非常简陋,编写时并没有考虑优化,显然还需要进行重构。
但关键是JavaCollectionsAPI从来无意将与集合相关的任何东西定死。
它总是需要扩展,同时也鼓励扩展。
当然,有些扩展比较复杂,例如
java.util.concurrent
中引入的扩展。
但是另一些则非常简单,只需编写一个定制算法,或者已有Collection
类的简单的扩展。
扩展JavaCollectionsAPI看上去很难,但是一旦开始着手,您会发现远不如想象的那样难。
中的Collections类旨在通过取代数组提高Java性能。
从之前了解到的,它们也是多变的,能够以各种方式定制和扩展,帮助实现优质、简洁的代码。
Collections非常强大,但是很多变:
使用它们要小心,滥用它们会带来风险。
6.List不同于数组
Java开发人员常常错误地认为
就是Java数组的替代品。
Collections由数组支持,在集合内随机查找内容时性能较好。
与数组一样,集合使用整序数获取特定项。
但集合不是数组的简单替代。
要明白数组与集合的区别需要弄清楚顺序
和位置
的不同。
例如,List
是一个接口,它保存各个项被放入集合中的顺序,如清单1所示:
清单1.可变键值
publicclassOrderAndPosition
voiddumpArray(T[]array)
System.out.println("
============="
);
for(inti=0;
i<
array.length;
i++)
Position"
+i+"
:
+array[i]);
voiddumpList(List<
list)
list.size();
Ordinal"
+list.get(i));
argList=newArrayList<
(Arrays.asList(args));
dumpArray(args);
args[1]=null;
dumpList(argList);
argList.remove
(1);
当第三个元素从上面的
中被移除时,其“后面”的各项会上升填补空位。
很显然,此集合行为与数组的行为不同(事实上,从数组中移除项与从
中移除它也不完全是一回事儿—从数组中“移除”项意味着要用新引用或null覆盖其索引槽)。
7.令人惊讶的
Iterator!
无疑Java开发人员很喜爱Java集合
Iterator,但是您最后一次使用
接口是什么时候的事情了?
可以这么说,大部分时间我们只是将
随意放到
for()
循环或加强
循环中,然后就继续其他操作了。
但是进行深入研究后,您会发现
实际上有两个十分有用的功能。
第一,Iterator
支持从源集合中安全地删除对象,只需在
上调用
remove()
即可。
这样做的好处是可以避免ConcurrentModifiedException,这个异常顾名思意:
当打开
迭代集合时,同时又在对集合进行修改。
有些集合不允许在迭代时删除或添加元素,但是调用
的
方法是个安全的做法。
第二,Iterator
支持派生的(并且可能是更强大的)兄弟成员。
ListIterator,只存在于
中,支持在迭代期间向
中添加或删除元素,并且可以在
中双向滚动。
双向滚动特别有用,尤其是在无处不在的“滑动结果集”操作中,因为结果集中只能显示从数据库或其他集合中获取的众多结果中的10个。
它还可以用于“反向遍历”集合或列表,而无需每次都从前向后遍历。
插入
ListIterator
比使用向下计数整数参数
List.get()“反向”遍历
容易得多。
8.并非所有
都来自集合
Ruby和Groovy开发人员喜欢炫耀他们如何能迭代整个文本文件并通过一行代码将其内容输出到控制台。
通常,他们会说在Java编程中完成同样的操作需要很多行代码:
打开
FileReader,然后打开
BufferedReader,接着创建
while()
循环来调用
getLine(),直到它返回
null。
当然,在
try/catch/finally
块中必须要完成这些操作,它要处理异常并在结束时关闭文件句柄。
这看起来像是一个没有意义的学术上的争论,但是它也有其自身的价值。
他们(包括相当一部分Java开发人员)不知道并不是所有
都来自集合。
可以创建
Iterator,该迭代器知道如何凭空制造下一个元素,而不是从预先存在的
中盲目地处理:
清单2.迭代文件
//FileUtils.java
importjava.io.*;
publicclassFileUtils
publicstaticIterable<
readlines(Stringfilename)
throwsIOException
finalFileReaderfr=newFileReader(filename);
finalBufferedReaderbr=newBufferedReader(fr);
returnnewIterable<
(){
public<
code>
Iterator<
/code>
<
iterator(){
returnnew<
publicbooleanhasNext(){
ret
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java Collections API 您不知道的 件事 知道