使用这类方法有什么好处呢?显然,它使得我们有可能通过一种统一的方式处理所有数据类型。所有Builder方法的用法都和上例相似。
Java没有C风格的枚举量,为此,lang包提供了一个类型安全的Enum类型,填补了空白。Enum类是抽象的,如果你要创建枚举量,就要扩展Enum类。下面的例子清楚地说明了Enum的用法。
import org.apache.commons.lang.enum.Enum;
import java.util.Map;
import java.util.List;
import java.util.Iterator;
public final class OnTV extends Enum {
public static final OnTV IDOL=
new OnTV("Idol");
public static final OnTV SURVIVOR =
new OnTV("Survivor");
public static final OnTV SEINFELD =
new OnTV("Seinfeld");
private OnTV(String show) {
super(show);
}
public static OnTV getEnum(String show){
return (OnTV) getEnum(OnTV.class, show);
}
public static Map getEnumMap() {
return getEnumMap(OnTV.class);
}
public static List getEnumList() {
return getEnumList(OnTV.class);
}
public static Iterator iterator() {
return iterator(OnTV.class);
}
}
以后我们就可以按照下面的方式使用枚举变量:OnTV.getEnum("Idol")。该调用从前面创建的枚举数据类型返回Idol。这个例子比较简单,实际上Enum类还提供了许多有用的方法,请参见本文后面提供的完整实例。
2.4 Collections
■ 概况:扩展了Java Collection框架,增添了新的数据结构、迭代机制和比较操作符。
■ 何时适用:几乎所有需要操作数据结构的重要Java开发项目都可以使用Collections API。和Java的标准实现相比,Collections API有着诸多优势。
■ 示例应用:CollectionsDemo.java。要求CLASSPATH中包含commons-collections.jar。
■ 说明:
要在有限的文章篇幅之内详尽地介绍 Collections API实在是太困难了,不过这里仍将涵盖大多数最重要的类,希望能够引起你的兴趣,认真了解一下其余的类。Collections本身的文档也提供了许多资料并解释了每一个类的用法。
Bag接口扩展标准的Java Collection,允许生成计数器来跟踪Bag里面的所有元素。当你想要跟踪进出某个集合的元素的总数时,Bag是非常有用的。由于Bag本身是一个接口,所以实际使用的应该是实现了该接口的类,例如HashBag或TreeBag--从这些类的名字也可以看出,HashBag实现的是一个 HashMap的Bag,而TreeBag实现的是TreeMap的Bag。Bag接口中两个最重要的方法是:getCount(Object o),用来返回Bag里面特定对象的出现次数;uniqueSet(),返回所有唯一元素。
Buffer接口允许按照预定义的次序删除集合中的对象,删除次序可以是LIFO(Last In First Out,后进先出),或FIFO(First In First Out,先进先出),另外还可以是自定义的次序。下面来看看如何实现一个Buffer,按照自然次序删除元素。
BinaryHeap类实现了Buffer接口,能够按照自然次序删除元素。如果要颠倒次序,则必须传入一个false,告诉Heap采用自然次序的逆序。
BinaryHeap heap = new BinaryHeap();
// …
// 将元素加入该Heap
heap.add(new Integer(-1));
heap.add(new Integer(-10));
heap.add(new Integer(0));
heap.add(new Integer(-3));
heap.add(new Integer(5));
//…
// 删除一个元素
heap.remove();
调用该Heap的remove,按照自然次序,元素集合中的-10将被删除。如果我们要求按照逆序排序,则被删除的将是5。
FastArrayList、FastHashMap和FastTreeMap类能够按照两种模式操作,超越了与它们对应的标准 Collection。第一种模式是"慢模式",类的修改操作(添加、删除元素)是同步的。与此相对,另一种模式是"快模式",对这些类的访问假定为只读操作,因此不需要同步,速度较快。在快模式中,结构性的改动通过下列方式完成:首先克隆现有的类,修改克隆得到的类,最后用克隆得到的类替换原有的类。 FastArrayList、FastHashMap和FastTreeMap类特别适合于那种初始化之后大部分操作都是只读操作的多线程环境。
iterators包为各种集合和对象提供标准Java Collection包没有提供的迭代器。本文的示例应用示范了ArrayIterator,通过迭代方式访问Array的内容。iterators包里面各种迭代器的用法基本上与标准Java迭代器一样。
最后,comparators包提供了一些实用的比较符。所谓比较符其实也是一个类,它定义的是如何比较两个属于同一类的对象,决定它们的排序次序。例如,在前面提到的Buffer类中,我们可以定义自己的比较符,用自定义的比较符来决定元素的排序次序,而不是采用元素的自然排序次序。下面来看看具体的实现经过。
// …
// ① 创建一个BinaryHeap类,但这一次参数中
// 指定NullComparator。NullComparator比较
// null与其他对象,根据nullsAreHigh标记来
// 判断null值比其他对象大还是小:如果
// nullsAreHigh的值是false,则认为null要比
// 其他对象小。
BinaryHeap heap2 = new BinaryHeap
(new NullComparator(false));
// …
// ② 将一些数据(包括几个null值)加入heap:
heap2.add(null);
heap2.add(new Integer("6"));
heap2.add(new Integer("-6"));
heap2.add(null);
// …
// ③ 最后删除一个元素,Bag包含的null将减少
// 一个,因为null要比其他对象小。
heap2.remove();
有关其他类Commons组件的介绍就到这里结束。如果你想了解更多细节信息,请参见API文档,最好再看看这些包的源代码。
三、Web类
Web类的组件用来执行与Web相关的任务。
3.1 FileUpload
■ 概况:一个可以直接使用的文件上载组件。
■ 官方资源:主页。由于这个组件尚未正式发布,今年二月发布的Beta版又有许多BUG,所以建议从nightly builds下载最新的版本。
■ 何时适用:当你想要在Java服务器环境中加入一个易用、高性能的文件上载组件之时。
■ 示例应用:fileuploaddemo.jsp,fileuploaddemo.htm,和msg.jsp。要求服务器端应用目录的WEB-INF/lib下面有commons-fileupload-1.0-dev.jar。
■ 说明:
FileUpload组件解决了常见的文件上载问题。它提供了一个易用的接口来管理上载到服务器的文件,可用于JSP和 Servlet之中。FileUpload组件遵从RFC1867,它分析输入请求,向应用程序提供一系列上载到服务器的文件。上载的文件可以保留在内存中,也可以放入一个临时位置(允许配置一个表示文件大小的参数,如果上载的文件超过了该参数指定的大小,则把文件写入一个临时位置)。另外还有一些参数可供配置,包括可接受的最大文件、临时文件的位置等。
下面介绍一下使用FileUpload组件的步骤。
首先创建一个HTML页面。注意,凡是要上载文件的表单都必须设置enctype属性,且属性的值必须是multipart/form-data,同时请求方法必须是POST。下面的表单除了上载两个文件,另外还有一个普通的文本输入框:
<form name="myform" action="fileuploaddemo.jsp"
method="post" enctype="multipart/form-data">
输入你的名字:<br />
<input type="text" name="name" size="15"/><br />
图形:<br />
<input type="file" name="myimage"><br/>
文件:<br />
<input type="file" name="myfile"><br /><br />
<input type="submit" name="Submit"
value="Submit your files"/>
接下来创建JSP页面。
// …
// ① 检查输入请求是否为multipart的表单数据。
boolean isMultipart = FileUpload.
isMultipartContent(request);
// …
// ② 为该请求创建一个句柄,通过它来解析请求。执行
// 解析后,所有的表单项目都保存在一个List中。
DiskFileUpload upload = new DiskFileUpload();
// 通过句柄解析请求,解析得到的项目保存在一个List中
List items = upload.parseRequest(request);
// …
// ③ 通过循环依次获得List里面的文件项目。要区分表示
// 文件的项目和普通的表单输入项目,使用isFormField()
// 方法。根据处理请求的要求,我们可以保存上载的文
// 件,或者一个字节一个字节地处理文件内容,或者打
// 开文件的输入流。
Iterator itr = items.iterator();
while(itr.hasNext()) {
FileItem item = (FileItem) itr.next();
// 检查当前的项目是普通的表单元素,还是一个上载的文件
if(item.isFormField()) {
// 获得表单域的名字
String fieldName = item.getFieldName();
// 如果表单域的名字是name…
if(fieldName.equals("name"))
request.setAttribute("msg",
"Thank You: " + item.getString());
} else {
// 该项目是一个上载的文件,把它保存到磁盘。
// 注意item.getName()
// 会返回上载文件在客户端的完整路径名称,这似乎是一个BUG。
// 为解决这个问题,这里使用了fullFile.getName()。
File fullFile = new File(item.getName());
File savedFile = new File
(getServletContext().getRealPath("/"),
fullFile.getName());
item.write(savedFile);
}
}
我们可以通过上载句柄的upload.setSizeMax来限制上载文件的大小。当上载文件的大小超过允许的值时,程序将遇到异常。在上面的例子中,文件大小的限制值是-1,表示允许上载任意大小的文件。
还有其他一些略有变化的使用形式,正如前面所指出的,我们可以在上载的文件上打开一个输入流,或者让它们驻留在内存中直至空间占用达到一定的限制值,或者在判断文件类型的基础上,以String或Byte数组的形式获取其内容,或者直接删除文件。这一切都只要使用FileItem类提供的方法就可以方便地做到(DefaultFileItem是FileItem的一个实现)。