您的位置:首页 > 编程语言 > Java开发

23.JAVA编程思想——实用工具

2016-04-17 09:25 459 查看
23.JAVA编程思想——实用工具

 

Collections 类中含有其他大量有用的实用工具:

enumeration(Collection) 为自变量产生原始风格的Enumeration(枚举)

max(Collection),min(Collection)在自变量中用集合内对象的自然比较方法产生最大或最小元素

max(Collection,Comparator),min(Collection,Comparator)在集合内用比较器产生最大或最小元素

nCopies(int n, Object o) 返回长度为n 的一个不可变列表,它的所有句柄均指向o

subList(List,int min,int max) 返回由指定参数列表后推得到的一个新列表。可将这个列表想象成一个“窗口”,它自索引为min 的地方开始,正好结束于max 的前面注意min()和max()都是随同Collection对象工作的,而非随同List,所以不必担心Collection是否需要排序(就象早先指出的那样,在执行一次binarySearch()——即二进制搜索——之前,必须对一个List 或者一个数组执行sort())。

1     使Collection 或Map 不可修改

通常,创建Collection 或Map 的一个“只读”版本显得更有利一些。Collections 类允许我们达到这个目标,方法是将原始容器传递进入一个方法,并令其传回一个只读版本。这个方法共有四种变化形式,分别用于Collection(如果不想把集合当作一种更特殊的类型对待)、List、Set 以及Map。下面这个例子演示了为它们分别构建只读版本的正确方法:

1.1     代码如下:

import java.util.*;

public
class
ReadOnly {

    public
staticvoid
main(String[]
args){

        Collection
c = new ArrayList();

        Collection1.fill(c);
// Insert useful data

        c =
Collections.unmodifiableCollection(c)
;

        Collection1.print(c);
// Reading is OK

        // ! c.add("one"); // Can't change it

        List a =
new ArrayList();

        Collection1.fill(a);

        a =
Collections.unmodifiableList(a)
;

        ListIterator
lit = a.listIterator();

        System.out.println(lit.next());
// Reading OK

        // ! lit.add("one"); // Can't change it

        Set s =
new HashSet();

        Collection1.fill(s);

        s =
Collections.unmodifiableSet(s)
;

        Collection1.print(s);
// Reading OK

        // ! s.add("one"); // Can't change it

        Map m =
new HashMap();

        Map1.fill(m, Map1.testData1);

        m =
Collections.unmodifiableMap(m)
;

        Map1.print(m);
// Reading OK

        // ! m.put("Ralph", "Howdy!");

    }

} /// :~

1.2     执行如下:

01 2 3 4 5 6 7 8 9

0

01 2 3 4 5 6 7 8 9

Key= Sleepy, Value = Prefers dark, quiet places

Key= Happy, Value = Cheerful disposition

Key= Sneezy, Value = Struggles with allergies

Key= Grumpy, Value = Needs to work on attitude

Key= Doc, Value = Fantasizes about advanced degree

Key= Dopey, Value = 'A' for effort

Key= Bashful, Value = Needs self-esteem workshop

对于每种情况,在将其正式变为只读以前,都必须用有有效的数据填充容器。一旦载入成功,最佳的做法就是用“不可修改”调用产生的句柄替换现有的句柄。这样做可有效避免将其变成不可修改后不慎改变其中的内容。在另一方面,该工具也允许我们在一个类中将能够修改的容器保持为private 状态,并可从一个方法调用中返回指向那个容器的一个只读句柄。这样一来,虽然我们可在类里修改它,但其他任何人都只能读。为特定类型调用“不可修改”的方法不会造成编译期间的检查,但一旦发生任何变化,对修改特定容器的方法的调用便会产生一个UnsupportedOperationException
违例。

2     Collection 或Map 的同步

synchronized 关键字是“多线程”机制一个非常重要的部分。我们到第14 章才会对这一机制作深入的探讨。只需注意到Collections 类提供了对整个容器进行自动同步的一种途径。它的语法与“不可修改”的方法是类似的:

2.1     代码如下:

import java.util.*;

public
class
Synchronization {

    public
staticvoid
main(String[]
args){

        Collection
c
= Collections.synchronizedCollection(new ArrayList());

        List list =
Collections.synchronizedList(new ArrayList());

        Set s =
Collections.synchronizedSet(new HashSet());

        Map m =
Collections.synchronizedMap(new HashMap());

    }

} /// :~

2.2     执行说明:

在这种情况下,我们通过适当的“同步”方法直接传递新容器;这样做可避免不慎暴露出未同步的版本。新集合也提供了能防止多个进程同时修改一个容器内容的机制。若在一个容器里反复,同时另一些进程介入,并在那个容器中插入、删除或修改一个对象,便会面临发生冲突的危险。我们可能已传递了那个对象,可能它位位于我们前面,可能容器的大小在我们调用size()后已发生了收缩——我们面临各种各样可能的危险。针对这个问题,新的集合库集成了一套解决的机制,能查出除我们的进程自己需要负责的之外的、对容器的其他任何修改。若探测到有其他方面也准备修改容器,便会立即产生一个ConcurrentModificationException(并发修改违例)。我们将这一机制称为“立即失败”——它并不用更复杂的算法在“以后”侦测问题,而是“立即”产生违例。

3     小结:

由标准Java(1.0 和1.1)库提供的集合(BitSet 未包括在这里,因为它更象一种负有特殊使

命的类):

(1) 数组包含了对象的数字化索引。它容纳的是一种已知类型的对象,所以在查找一个对象时,不必对结果进行造型处理。数组可以是多维的,而且能够容纳基本数据类型。但是,一旦把它创建好以后,大小便不能变化了。

(2) Vector(矢量)也包含了对象的数字索引——可将数组和Vector 想象成随机访问集合。当我们加入更多的元素时,Vector 能够自动改变自身的大小。但Vector 只能容纳对象的句柄,所以它不可包含基本数据类型;而且将一个对象句柄从集合中取出来的时候,必须对结果进行造型处理。

(3) Hashtable(散列表)属于Dictionary(字典)的一种类型,是一种将对象(而不是数字)同其他对象关联到一起的方式。散列表也支持对对象的随机访问,事实上,它的整个设计方案都在突出访问的“高速度”。

(4) Stack(堆栈)是一种“后入先出”(LIFO)的队列。

若你曾经熟悉数据结构,可能会疑惑为何没看到一套更大的集合。从功能的角度出发,你真的需要一套更大的集合吗?对于Hashtable,可将任何东西置入其中,并以非常快的速度检索;对于Enumeration(枚举),可遍历一个序列,并对其中的每个元素都采取一个特定的操作。那是一种功能足够强劲的工具。但Hashtable 没有“顺序”的概念。Vector 和数组为我们提供了一种线性顺序,但若要把一个元素插入它们任何一个的中部,一般都要付出“惨重”的代价。除此以外,队列、拆散队列、优先级队列以及树都涉及到元素的“排序”——并非仅仅将它们置入,以便以后能按线性顺序查找或移动它们。这些数据结构也非常有用,这也正是标准C++中包含了它们的原因。考虑到这个原因,只应将标准Java
库的集合看作自己的一个起点。而且倘若必须使用Java 1.0 或1.1,则可在需要超越它们的时候使用JGL。

如果能使用Java 1.2,那么只使用新集合即可,它一般能满足我们的所有需要。注意本书在Java 1.1 身上花了大量篇幅,所以书中用到的大量集合都是只能在Java1.1 中用到的那些:Vector 和Hashtable。就目前来看,这是一个不得以而为之的做法。但是,这样处理亦可提供与老Java 代码更出色的向后兼容能力。若要用Java1.2 写新代码,新的集合往往能更好地为你服务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: