2009年4月15日星期三

Google pk Apache:谁的集合库更酷

http://www.lupaworld.com/viewnews-35504-page-3.html

Google pk Apache:谁的集合库更酷

来源: LUPA开源社区

发布时间: 2008-01-07 09:36 作者: 海天一色 来源: IT168 版权申明 LUPA投递新闻

字体: | 上一篇 下一篇 | 打印

 

文章来源于http://www.lupaworld.com

  集合是编程语言中的一个非常重要的特性,在ApacheCommon程序集中为我们提供了一套更为强大的集合库。而最近火暴的Google也推出了自己的集合库,这套集合库不仅增强了我们感兴趣的功能,而且还使整个Java集合框架得到了空前的增强。LUPA开源社区XXp0p}Z%{n`%H

vX.pOq‑cD
   当我第一次使用Google的集合库时就有些困惑。这套Google集合库是为增加JDKJava集合库框架而设计的,它的开发人员计划使这套库成为 JDK7的一部分。但在这之前,Apache组织已经在Common中加入了集合类库,正是由于这一点,使我不明白的是一向以创新精神著称的Google 为什么要做Apache已经做过的事。不过,最后我看了下关于对这套库的创始人的采访才了解Google的最终动机是为了使这套库提供对泛型的支持,而 Apache的这套集合库目前并不支持泛型,而且Apache的这套库还有一些类明显违反了Java集合框架的规范。LUPA开源社区p5h0T']o Z[-nq


Wo
[‑UtM Im;p
  为了验证Apache的这套集库是否真的如Google所说的那样,我特意查看了一下Apache的这套库,结果发现它确实不支持JDK5的泛型功能(这是一个非常明显的缺陷),但在SourceForge网站上的确声称支持泛型。
@6X5@2{9Y
h8R\M8w


I
F[1]h
LB)\
   至于那个违反Java集合框架规范的地方,我发现只有在Apache集合类中的Bag接口方法违反了这个规范,这是由于Bag接口本身的特性所决定的。 如在Bag接口的add方法中,在Java集合框架的规范中规定add方法必须总是返回true,但当同类型的对象在Bag中存在时,add方法并不返回 true。在这种情况下,在这种情况下,它仅仅增加计数,并返回falseApache集合类还有一个一致性问题,我发现这套库的源程序和二进制程序有 些不一致,src文件夹已经有很长时间没有更新了。LUPA开源社区 g&S iY
?
ujx
cD

LUPA
开源社区G­hV TQ z
  基于以上的原因,我决定更深一步地研究Google的这套开源集合类库,并发现在其中更有价值的东西。在本文中首先描述了Google集合库的包和类(只是简单的提一下),然后会将ApacheGoogle的这两套集合类库进行一个比较,看看其中的差别。
U&o!n
l6x0r5\LUPA开源社区QH-] e,C!e
  Google的这套集合库共分为两个包:
`D
idQr7R

9M"e*Lc:L/AK@y
  1. com.google.common.base:这个包由一些常用的类组成,在些类甚至可以在没有Java集合框架来的情况下使用。
­Z{!Qu0Q0eQp
  2. com.google.common.collect:这个包所提供的类将大大增强原有的Java集合框架。
"e'kiHG
w;t

Yt
c3~k
RK*e
U/`
  下面分别介绍一下这两个包,并将其和Apache的集合库做一下比较:
:c j9ls
Z%_(R+z

j \#X
e[
L3ko,g
  . The com.google.common.base PackageLUPA开源社区s L$Y‑v+n8r5R[1]Yd#L4n

J9LB
Xf;n
   在这部分将讨论一下在com.google.common.base中的这个通用类包。如果我们直接使用过在Java集合框架包 java.lang.ref中的任何SoftReferenceWeakReferencePlantomReference类,以及使用 ReferenceQueue写过代码,我们会为使用Google的这套库而兴奋不已。下面是Google的三个和java.lang.ref包对应的 类:LUPA开源社区;MFE‑E!kY
N(j m


e&i)C&Z*_ g1V

q,Q _‑~#tC-tT­h
1. FinalizablePhantomReference LUPA
开源社区!P
P Ob5c(Hn

2   FinalizableSoftReference
[‑H­`sg*`#u3. FinalizableWeakReferenceLUPA
开源社区~R.d7Dt+[B

Ar:e2ei
kw
D+?
   上述的三个类扩展了它们各自在Java集合类中对应的类,这些都都可以处理ReferenceQueue,并回调在这些类中定义的 finalizeReferent()方法。因为如果当一个对象被垃圾回收器回收后,必须做一些清理工作时,finalizeReferent()方法将 是最好的选择。LUPA开源社区U2c{S0pw.J7eTg
LUPA
开源社区*r
ip5M4F
[7M$iu

   例如,假设我们正在使用ImageChunks类来将一个图象二进制数据保存在一个对象中,然后当JVM运行变得缓慢时,GC将清楚这个对象类型。我们 可以试着继承这个FinalizableSoftReference类,然后覆盖FinalizeReferent方法。这个方法允许我们在GC清除对象 时写一些清除操作的代码。FinalizableSoftReference的最大优势就是我们不需要直接处理ReferenceQueueLUPA开源社区&w+o,t s*O4I
LUPA
开源社区Ml
x­ZWJ‑}qv;b?-z

  要注意的是,这个包并不能取代ReferenceQueue,因为它并不是为增强类而设计的。

 

2. Function接口LUPA开源社区aN7@


^'oU}
LUPA
开源社区‑Eb­m4[4La-kY{
   Function接口中的方法将用来进行数据的类型转换,如将String类型转换为Integer类型。Fuction将被使用在 com.google.common.collect包中的MapsComparators中来执行转换任务。下面是几个非常典型的Function 应用:
#E(Q'V g8P
`0`LUPA开源社区7L_z5I+Z3qr1{+fE&jV
  (1)  Maps.uniqueIndex(...)使我们在支持Map实例的数据类型之间进行转换。这个谅无立锥之地 产生一个包含key和被转换的值的Map实例。LUPA开源社区
A [i
T!T(];V{2y


j(kue&r)a$\!D
   (2) Comparators.fromFunction(Function<F,T> function)方法可以让我们建立一个Comparator,个Comparator可以将两个值进行比较。Comparator在这个方法中被创 建,这些对象将以自然顺序进行比较。LUPA开源社区c8V
tx­}‑P,C


'bm0sQ‑p
ALQ$NM­@
  (3) Function中的forMap方法可以方便地在一个要进行转换地Map中查询。这个方法在一个Map实例中调用,并返回一个Function。当这个方法被调用时,将使用这个方法的输入参数作为关键字,在Map中查找数据。LUPA开源社区#c X]*G
y8Eg


(O)F d$iqR,V I
aw
   我们可以发现这个Function接口被使用在ListIteratorsIteratorFunctions类中。和Google的这个 Function接口相对应的Apache集合类的接口是org.apache.commons.collections.Transformer,它被 使用在以下几个类中:LUPA开源社区9{4P8SZJ1F6R;ju
LUPA
开源社区
`L&^‑j{-t
_A4I c9`

(1). TransformedBag LUPA
开源社区D+o ` A:e
A t

(2). TransformedBuffer LUPA
开源社区Qh0y!`p3t
]

(3). TransformedList LUPA
开源社区$[V5M\&c:jQ S
(4). TransformedSet
)Q0hy4Tqe(5). TransformedMap LUPA
开源社区2@_ E3`!Wn't7dm!v

)WR‑U1Sc6x+j8G
  3. Nullable
4D
D_kb,U7?-k
J-f

;P `9^j.\
]&u P
   Nullable注释类型是一个非常棒的东西。对于很多商业应用程序的开发人员有一个很常见的误会,就是它们的应用程序不能抛出运行时错误。而 Nullable允许运行时错误被接受,并以非常简捷的方式来将这个异常和方法绑定。也就是如果一个方法不能接收一个空参数,开发人员可以使用 Nullable来执行一个是否为空的检查,以及在方法的第一行抛出一个错误。LUPA开源社区,E:Cv
z!J/g3^

 
n7~4v
nZ t"C;w:Vq
  4. 对象和预处理类(ObjectsPreconditions)LUPA开源社区
M[1]ZJ7G1S.k


I
@c3Qm|}%l_&o;}5G
a
  ObjectsPreconditions可以在没有Java标准集合类的情况下使用:LUPA开源社区m(jO!_!{N/t
LUPA
开源社区;]/J1N‑o,W&^y
  (1). Objects类包含了一系列有用的方法来辅助调用toStringhashCode和其他Object类的方法。在它的内部使用了数组来表示对适当类型的调用。LUPA开源社区f*wI4sv

%Jnz'|v I J%N
  (2) Preconditions类是一个非常有用的类,它用来核对传递到一个方法的参数,并抛出一个适当的异常。
/z$HT.K%G!Uh­u:k {
G
z7^ Y%}+cLUPA
开源社区*]6@#Z6F m
P

  5. Predicates
6n5vl
bm7y
RRLUPA
开源社区P9`l6?/f
Wc ~O,c
N

  Predicates可以对扫描一个集合进行建模(如,当我们想扫描所有的雇员对象集合时,并通过salary属性来过滤他们)。使用Predicates可以为我们节省很多写重复代码(这些代码主要是对集合列表中的对象的核对)的时间。
0T
i0[6kj2I|(B"|

l+a:t,p[1][%^,R
  二、com.google.common.collect Package
'@.h MPYm
&C6J
W;sCQ*u
   
这部分将介绍一下Google的这个用于增强Java集合框架的包:com.google.common.collect
[1]K"E(fw B6Z7o%xLUPA
开源社区
qQy‑c K2`

  1. BiMapClassToInstanceLUPA开源社区 g`X ux7jw
 LUPA
开源社区#GEzo
ps])r

  在集合库中的BiMap接口和Apache的公用集合中的BidiMap接口类似。它允许我们将五个key映射到一个值上,并形成一个整体。因此,keyvalue应该是唯一的。LUPA开源社区@'hf:OR+rL

D;nV
?;A,lS
   
通过对这两个库的比较后发现,GoogleHashBiMapApacheDaulTreeBidiMap在插入和查询的时间非常类似。然 后,TreeBidiMap花了更长时间来插入数据,,但它更节省内存,这主要是因为它并不使用双重映射来表示keyvalueLUPA开源社区
b-n'sk‑\vr"NA
u

LUPA
开源社区$R(A y"x‑GLu
   如果我们的Keyvalue使用Enum类型,那么我们可以使用com.google.common.collect包中的EnumBiMap类直接 建立一个bi-directional映射。但我想这么做的人很少,毕竟将Enum类型映射到Enum类型的意义不大。
D4~"SW!T+w#]6e
7g _/W'd^$T(o"`
L'@
  在Google的这套库中并没有和ApacheClassToInstance 相对应的类,这个类可以用来将一个对象实例映射到它的class类型。LUPA开源社区;R;B|'Khs,~
B4_

 
ND$P)Avh4J:B
Yb N?W
  2. Comparators
%SK `%@ fI
]&SPkm{$[v
   在GoogleApache的库中都有Comparators,这个接口可以使我们建立一个Comparator来和集合一起使用。如果我们必须在应 用程序中大量使用Comparator,可详细看一下google提供文档。这些文档包含了Comparator的所有方法和使用。
[1]t m[1]a z6|#^0N9NLUPA
开源社区0}­J#H cqDq
  如果我们有两个comparators,并且想综合利用它们获得更佳的结果,可以很方便地使用Comparators.compound。这个方法返回了一个Comparator,这个Comparator将调用其他的comparator,直到发现了非空的结果。
,U3?6X1W­h
o7lLUPA开源社区
X$|,jD­v

   在org.apache.commons.collections.comparators包中包含了7个预定义的comparators方法。其中一 个是org.apache.commons.collections.ComparatorUtils,这个类和 com.google.common.collect.Comparators非常类似。和Apache的库不同,Google的这个 Comparator将所有的功能定义在了一个类中:Comparators。这个类包含原始比较方法,还有在比较之前转换数据的功能。
n:T3B6e‑U LUPA
开源社区(o3o­Nj:Q&{]F
  3. Maps, Lists,Sets    这三个类:MapsListsSets分别允许我们很方便地建立一个maplistset对象,在建立的过程中无需调用构造方法。如我们可以使用下面的代码来替换Map m = new HashMap()LUPA开源社区,a`4`
y[[1]D

LUPA
开源社区DU:]Pq R8l
  Map m = Maps.newHashMap();
I#{(W b3c
V$l.]l2kWLUPA
开源社区+rf6L0o‑fr
  除了建立集合对象外,这些工厂类还有很多实用的方法,主要的方法如下:LUPA开源社区s k'S+t$l

Ya‑s
~!a
b
  1. Maps.immutableMap(...)方法可以让我们建立一个不变的Map,用于保存一个固定的keyvalue的对集。我们不再需要写45行代码来创建一些硬编码的keyvalue的映射对。
‑~C‑oj6n)d
vo([

1Fr4p6X
D{)ZF
  2. List.newArrayList(Iterator itr)方法建立了一个ArrayList对象,并将参数itrArrayList对象组合在一起。LUPA开源社区O4hE!PX6^9Wg

$DR&m(G~,^
  在Apache的类库中也可以找到类似的类,如MapUtilsListUtilsSetUtilsLUPA开源社区 w r%KQ#b0[
LUPA
开源社区j
r c2z#B4N
yxQ

  这套库还包含了其他一些实用的类,如PrimitiveArraysObjectArrays,来简化简单类型的使用。PrimitiveArrays包含了有用的方法将List转换为简单类型。这将大大减少我们程序中的重复代码。

 

三、Google的集合库真的完美吗?
!u
Q
m6q
?0j
^7v

)M,c‑sR$B"]v4[     Google
的集合库虽然很强大,但是在其中也有不足的地方,如以下的功能在Apache的集合库有,但在Google的集合库中就没有:
#l+PQ‑B ju2Q4n
?2KT


Zl
~(@   1. org.apache.commons.collections.keyvalue.MultiKey:这个类允许我们使用多个值建立一个keyLUPA开源社区­U+C0F(_0D.h#PQ)M
LUPA
开源社区? {&nr
G

  2. org.apache.commons.collection.buffer:这个类为从集合中删除一个对象定义了一个契约。根据Buffer接口的文 档,"从集合中删除对象的顺序可以基于插入的顺序(如FIFO队列或是LIFO栈),访问顺序(如一个LRU缓冲),任何的Comparator的顺序 (如一个优先队列)或是任何其他明确定义的顺序"
!['`bSLR i*k
W[1]}
M
M
I

Hk h4`'t
  3. org.apache.commons.collections.functors:这个类并没有什么特殊的功能,只是当Predicate evaluate方法返回true时调用。LUPA开源社区8J
TX)Y:LGH#\


$f,@x6M%`:h}    
除了上述的三个在Google的集合库中未发现的功能外,还有FixedSizeListLazyList以及一些其他特殊的list类型类,如FixedSizeMapFlat3MapLazyMapLRUMap以及ListOrderedSetLUPA开源社区7uoo#g-Z+\;wC#h
LUPA
开源社区S2o f3\L9U
  四、我们到底该选哪个集合库
LUPA开源社区[1]b?5C)S;V
P

  虽然Google已经在它的GMailGoogle ReaderBlogger中大量使用了这套集合库,但它现在仍然未正式发行(版本号为0.5)。从这个版本号来看,Google的集合库仍然是Alpha版本。目前它的功能只有85%经过了测试。
O
yL'ng‑T1M
LUPA
开源社区A:u[1]B;|_2VCCw4]z
  现在我们已经知道Google的集合库和Apache的公共集合库的区别了。如果我们不是必须使用JDK5的泛型功能,那么Apache的集合库将是 最好的选择,因为它要比Google的这套库更成熟。但在我各人看来,我更喜欢Google的集合库中提供新特性的类和包,这些东西使更容易学习和使用。 如果Apache的集合库可以跟上时代的步伐,继续加入JDK5以及JDK的后续版本功能,那么Apache的集合库也许会更耀眼。

 

没有评论:

发表评论