org.apache.commons.collectionsJDK中不是已经有了Java集合框架了吗,为什么还要使用Apache的集合呢?

姬振濂
2023-12-01

JDK中不是已经有了Java集合框架了吗,为什么还要使用Apache的集合呢?这是因为Apache的集合时对JDK集合的一个补充和增强,它提供了更多的接口和实现类。甚至于它应该成为JDK的一部分。

原文http://blog.csdn.net/sunjavaduke/archive/2008/03/24/2214806.aspx

本文简要的介绍了Apache Commons中的collections框架内容。本文主要根据Apache官方网站的overview、userguide以及javadoc翻译而成。如有转载,请声明出处。

Commons Collections:
Java集合框架是JDK 1.3对JDK1.2的一个主要的补充。Java集合框架包含了很多强大的数据结构,这些数据结构加快了很多重要的Java程序的开发。从那之后,集合框架就已经成为Java处理集合的公开标准。
Commons-Collections以JDK的集合框架为基础,提供了新的接口、实现以及工具。它具有以下特点:
®        Bag接口:适用于包含一个对象的多个拷贝的集合
®        Buffer接口:适用于具有顺序的集合类,例如FIFOs(先进先出)
®        BidiMap(双向映射):可以通过值查找键,也可以通过键查找值
®        Map迭代器:提供了对映射的快速迭代
®        对类型检查进行了封装,确保特定类的实例可以被添加到集合中
®        对转换进行了封装,将集合中的对象转换成被加入时的类型
®        对集合进行组合,使多个集合看起来就像一个集合一样
®        有序映射和set,保持元素添加时的顺序,包括一个基于LRU的map
®        标识映射可以给予对象的==来比较对象,而不是基于equals方法
®        引用映射可以允许键and/or值可以有控制的进行回收
®        很多比较器的实现
®        很多迭代器的实现
®        从数组或者枚举到集合的适配器
®        用来测试或者创建典型set理论的集合属性,例如与、或、闭包
用户指南:
Commons-Collections为了帮助日复一日的编程,提供了大量的类。本部分主要介绍了一些Collections的关键特性。
注意同步
Commons-Collections使用了和标准Java集合类似的同步设计方法。如果不添加额外的同步方法,大多数关于集合、映射和bag的实现都不是线程安全的。集合的synchronizeXXX方法就是这些实现中的一种方式,可以使集合在多线程的应用程序中被同步。
类层次的javadoc应该指出如果没有额外的同步机制,在进行多线程访问时,某个特定的实现是否是安全的。如果没有特别指出是线程安全的,那么就被认为是需要进行同步的。
工具类:
每个主要的集合接口都有一个Utility类。因此,Set和SortedSet接口的Utility类就是SetUtils。这些Utility类提供了操作集合类型的共通方法。
基本的方法都包含在两个根集合接口的Utility类中,即CollectionUtils和MapUtils。因为所有的其他集合接口都集成Collection或者Map,所以CollectionUtils和MapUtils可以被扩展使用。共同的方法包括交集操作、计数操作、迭代操作、逻辑操作和类型强制转换操作等。同时,utility类还提供了对集合封装类的访问,这与JDK Collections类的方式类似。
Maps:
Map迭代
JDK中的Map接口很难进行迭代。API用户总是需要通过EntrySet或者KeySet进行迭代。Commons-Collectons现在提供了一个新的接口—MapIterator来允许对maps进行简单的迭代。
IterableMap map = new HashMap();
MapIterator it = map.mapIterator();
While(it.hasNext()){
       Object key = it.next();
       Object value = it.getValue();
       It.setValue(newValue);
}
有序Map
Commons-Collections为maps提供了一个新的接口,OrderedMap,这个接口是有顺序的,但是并没有进行排序。LinkedMap和ListOrderedMap(封装器)是这个接口的两种实现。这个接口支持map迭代,同时允许对map进行前向迭代和反向迭代。
OrderedMap map = new HashMap();
map.put(“FIVE”,5);
map.put(“SIX”,6);
map.put(“SEVEN”,7);
map.firstKey();                   //returns “FIVE”
map.nextKey(“FIVE”);         //returns “SIX”
map.nextKey(“SIX”);           //returns “SEVEN”
BidDirectional Maps双向映射
Commons-Collections提供了新的接口层次,用于支持双向的映射,即BidiMap接口。可以通过key来查找value,也可以通过value来查找key。
BidiMap bidi = new TreeBidiMap();
bidi.put(“SIX”,”6”);
bidi.get(“SIX”);            //returns “6”
bidi.getKey(“6”);          //returns “SIX”
bidi.removeValue(“6”);              //removes the mapping
BidiMap inverse = bidi.inverseBidiMap();              //returns a map with keys and values swapped
对于有序的和排序的双向map,也公共了对应的接口。对于每种双向map类型都提供了接口的实现。
Queues&Buffers 队列和缓冲
Buffer接口用来支持队列和缓冲。这些接口表示集合可以定义删除的顺序。
Buffer buffer = new UnboundedFifoBuffer();
buffer.add(“ONE”);
buffer.add(“TWO”);
buffer.add(“THREE”);
buffer.remove();   //removes and returns the next in order,”ONE” as this is a FIFO
buffer.remove();   //removes and returns the next in order,”TWO” as this is a FIFO
FIFO(队列)、LIFO(堆栈)和Priority(根据比较器的顺序)的接口实现已经被提供。
Bags
Bag接口用于支持bag。它用于表示包含了一个对象的多个拷贝的结合。
Bag bag = new HashBag();
bag.add(“ONE”,6);             //add 6 copies of “ONE”
bag.remove(“ONE”,2);              //removes 2 copies of “ONE”
bag.getCount(“ONE”);              //returns 4
对于排序和为排序的Bag,具有对应的接口实现。
下面是对Internet中一篇文章的翻译,原文出处: http://www.devx.com/Java/Article/29392/0/page/3
JDK中不是已经有了Java集合框架了吗,为什么还要使用Apache的集合呢?这是因为Apache的集合时对JDK集合的一个补充和增强,它提供了更多的接口和实现类。甚至于它应该成为JDK的一部分。
下面是一些笔者比较喜欢的特性:
®        bag接口
®        固定大小的map、LRU (最近最少使用算法)map和双重(dual)map
®        对象数组和map的迭代器
®        map的MultiKey
®        大量的工具类,提供了使用API的快捷方式
®        封装器,对大多数类提供了自定义的方法
Collections类根据下面列举的包结构进行组织:
org.apache.commons.collections
org.apache.commons.collections.bag
org.apache.commons.collections.bidimap
org.apache.commons.collections.buffer
org.apache.commons.collections.collection
org.apache.commons.collections.comparators
org.apache.commons.collections.functors
org.apache.commons.collections.iterators
org.apache.commons.collections.keyvalue
org.apache.commons.collections.list
org.apache.commons.collections.map
org.apache.commons.collections.set
org.apache.commons.collections
这个包中定义了由其他包实现的接口、作为工厂类(可以实例化集合类或者集合的封装类)的共通类。一些比较重要的类有ArrayStack、BeanMap、ExtendedProperties、FastArrayList、FastHashMap和FastTreeMap。这些类的细节包含在Javadoc中,下面只是简要的介绍各个类在实际中的应用:
ArrayStack:ArrayStack类实现了Stack接口,基于ArrayList用来在单线程环境中使用。例如,如果想在一个方法中使用Stack进行一些处理,这个类在性能上会比Stack(JDK1.4.2中使用Vector)好一些。
BeanMap:就像Swing GUI中的JButton一样,使用BeanMap,甚至可以将一个map作为一个JavaBean来进行处理。当在设计用来显示数据源或者应用程序配置属性的GUI时,map可以在屏幕上被拖放(D&D)。
ExtendedProperties:这是一个非常有用的类。它和java.util.Properties类似,包含了一个用于加载配置信息的load方法,但是这个类有以下的好处:
# 属性值可以分布在多行
# 提供了用于获取非字符串值的方法。例如,getFload方法用于获取一个fload类型的值。这样就不需要使用wrapper方法来转换获取的字符串值了。
FastArrayList, FastHashMap, FastTreeMap:这些类可以在多线程环境中使用,如果存在很多只读操作的话。这些类是分别基于ArrayList、HashMap和TreeMap的。
org.apache.commons.collections.bag
如果需要将一个对象的多个拷贝添加到一个List中时,这个包下面的类就变得非常有用了。在这种情况下,很多开发人员会将对象添加到一个ArrayList中,然后每天加一次都要进行一下迭代,来判断是否添加了给定类型的对象。在线购物车是这种情况的一个实际的需求。这种方法的缺点是内存和速度上的不足。
解决上述需求的一个比较好的设计就是只保存一个对象的拷贝,而在添加同样类型的实体时,只是增加计数器的值。HashBag和TreeBag类(分别基于HashMap和TreeMap)很好的满足了这个需求。

如下面的例子所示:
package in.co.narayanan.commons.collections.bag;
import junit.framework.TestCase;
import org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.HashBag;
/**
* This domain represents an order placed by the customer.

* @author Narayanan A R
*/
public class Order {
       private Bag orderedProducts;
       public Order() {
              orderedProducts = new HashBag();
       }
       public void addProduct(Product p) {
              orderedProducts.add(p);
       }
       public int countWindowsLicenses() {
              return orderedProducts.getCount(Product.WINDOWS);
       }
       public int countLinuxLicenses() {
              return orderedProducts.getCount(Product.LINUX);
       }
}
class Product {
       //OsType is an enum
       public static final Product WINDOWS = new Product(OsType.WINDOWS);
       public static final Product LINUX = new Product(OsType.LINUX);
       public static final Product MAC = new Product(OsType.MAC);
       public static final Product HPUNIX = new Product(OsType.HPUNIX);
       private int quantity;
       private int version;
       private float prize;
       private OsType type;
       public Product(OsType type) {
              this.type = type;
       }
       public int getQuantity() {
              return quantity;
       }
       public void setQuantity(int quantity) {
              this.quantity = quantity;
       }
       public int getVersion() {
              return version;
       }
       public void setVersion(int version) {
              this.version = version;
       }
       public float getPrize() {
              return prize;
       }
       public void setPrize(float prize) {
              this.prize = prize;
       }
       public OsType getType() {
              return type;
       }
       public void setType(OsType type) {
              this.type = type;
       }
       @Override
       public boolean equals(Object o) {
              if (o instanceof Product) {
                     return ((Product) o).getType().equals(this.getType());
              }
              return super.equals(o);
       }
       @Override
       public int hashCode() {
              return type.hashCode();
       }
       @Override
       public String toString() {
              return type.toString();
       }
}
class TestOrder extends TestCase {
    public void testOrder() {
        Order order = new Order();
        order.addProduct(new Product(OsType.WINDOWS));
        order.addProduct(new Product(OsType.WINDOWS));
        order.addProduct(new Product(OsType.WINDOWS));
        order.addProduct(new Product(OsType.LINUX));
        order.addProduct(new Product(OsType.LINUX));
        order.addProduct(new Product(OsType.HPUNIX));
        order.addProduct(new Product(OsType.MAC));
        int licenses;
        licenses = order.countWindowsLicenses();
        assertEquals(3, licenses);
        licenses = order.countLinuxLicenses();
        assertEquals(2, licenses);
    }
}
通过调试,运行到上述红色行时,order的成员变量orderedProducts的内容为:(toString显示内容)
[2:LINUX,1:MAC,1:HPUNIX,3:WINDOWS]
即实际上只存储了一个对象的拷贝,然后使用数字进行标识个数。
而orderedProducts的成员HashMap对象的size为4。
org.apache.commons.collections.bidimap

很多Java开发人员通过使用两个HashMap来获取一个键值,方法是将一个值作为键传递到另外一个HashMap。正常情况下,需要对同等的处理名字和值,在这种情况下,就是值也可以做为键(因为在map中键是唯一的,而值是可以不唯一的)。
关于org.apache.commons.collections.bidimap的例子是一个原型适配器,集成了PeopleSoft和Siebel命令行处理引擎,假定一个引擎中的每个命令在另外一个中都有同样的对应。可以在in.co.narayanan.commons.collections.bidimap中找到相关的类。可以通过SiebelPeopleSoftConnector来了解这些类,SiebelPeopleSoftConnector作为适配器,并包含了BidiMap对象。当收到处理Siebel命令的请求后,就从BidiMap获取对应的PeopleSoft命令,然后传送给PeopleSoft命令引擎。反之亦然。样例代码中只包含应用程序的一个轮廓。
/**
*Definescontractforthesystemstoconsumeagiven
*command.
*
*@authorNarayananAR
*/
publicinterface ICommandConsumer {
    Object consume(String command, Object arg);
}
class SiebelCommandConsumer implements ICommandConsumer {
    public Object consume(String command, Object arg) {
        System.out.println("Processing Siebel command:" + command);
        System.out.println("Arg:" + arg);
        return"SIEBEL:" + command + "-SUCCESSFUL";
    }
}
class PeopleSoftCommandConsumer implements ICommandConsumer {
    public Object consume(String command, Object arg) {
        System.out.println("Processing PeopleSoft command:" + command);
        System.out.println("Arg:" + arg);
        return"PEOPLESOFT:" + command + "-SUCCESSFUL";
    }
}
import org.apache.commons.collections.bidimap.TreeBidiMap;
import org.apache.commons.collections.BidiMap;
/**
*Responsibleforadaptingboththesystem'scommands.
*
*@authorNarayananAR
*/
publicclass SiebelPeopleSoftConnector {
    private ICommandConsumer peopleSoft;
    private ICommandConsumer siebel;
    private BidiMap commandMap;
    public SiebelPeopleSoftConnector(ICommandConsumer peopleSoft,
                                     ICommandConsumer siebel) {
        this.peopleSoft = peopleSoft;
        this.siebel = siebel;
        commandMap = prepareCommandMapping();
    }
    private BidiMap prepareCommandMapping() {
        BidiMap map = new TreeBidiMap();
        map.put("start", "init");
        map.put("exit", "quit");
        map.put("delete", "remove");
        return map;
    }
    /**
     *DelegatesthecalltothePeopleSoftcommandenginebyfetchingthemappedcommand.
     *
     *@paramcommandSiebelcommand
     *@paramargArgumentifany
     *@returnResultreturnedfromPeopleSoftcommandengine
     */
    public Object processSiebelCommand(String command, Object arg) {
        returnpeopleSoft.consume((String)commandMap.get(command), arg);
    }
    /**
     *DelegatesthecalltotheSiebelcommandenginebyfetchingthemappedcommand.
     *
     *@paramcommandPeopleSoftcommand
     *@paramargArgumentifany
     *@returnResultreturnedfromSiebelcommandengine
     */
    public Object processPeopleSoftCommand(String command, Object arg) {
        returnsiebel.consume((String)commandMap.getKey(command), arg);
    }
}
即可以根据key查找value,也可以根据value查找key。

org.apache.commons.collections.buffer
这个包中包含了封装类,直接实现了java.util.Collection接口。因此,任何实现Collection接口的类都可以使用这些封装类。比较常用的类有PredicatedCollection、CompositeCollection、SynchronizedCollection、TransformedCollection、TypedCollection和UnmodifiableCollection。下表提供了关于这些类的一个概览:
PredicatedCollection:可以通过使用这个类的实例来追加限制条件,将条件定义成一个独立的对象,也就是所谓的前提条件,然后作为参数传送给封装类的工厂方法。
▶           CompositeCollection:使用这个类可以创建集合的集合,并且当添加或者删除对象时具有一个统一的视图。
▶           SynchronizedCollection:可以使既存的集合线程安全。
▶           TransformedCollection:当将对象添加到集合时转换对象的类型。例如由String-->Integer。
▶           TypedCollection:与Java 1.5类似的泛型。
▶           UnmodifiableCollection:使集合的引用不可以被修改。
org.apache.commons.collections.comparators
这个包中包含了很多可复用的类。NullComparator类和FixedOrderComparator是最常用的类。
NullComparator:当对数组或者列表中的实体进行排序时,将null实体移到底部。
FixedOrderComparator:将一个集合中的顺序重新保存在预定义的列表中。
org.apache.commons.collections.functors
org.apache.commons.collections.iterators
在这个包中包含了很多实现了java.util.Iterator接口的类。比较重要的类有MapIterator、ArrayIterator、CollatingIterator、LoopingIterator和IteratorUtils。需要通过使用IteratorUtils类来使用这个包中的类。
org.apache.commons.collections.keyvalue
这个包中的MultiKey类非常有用。如果想要在应用程序中创建一个域(domain)对象并将它们存储在一个基于联合逐渐的map中,就可以通过创建一个MultiKey的实例,使用记录的主键的值作为参数。然后将这个实例传递给map来存储域对象。
这个包中的类的其他用途是存储locale相关的实体,在这种情况下,实际的主键和locale name联合组成key。
org.apache.commons.collections.list
TreeList、FixedSizeList、NodeCachingLinkedList、CursorableLinkedList、TransformedList和PredicatedList类都是这个包中比较重要的类。它们的javadoc也非常清楚的描述了各自的功能。
org.apache.commons.collections.map
CaseInsensitiveMap、CompositeMap、FixedSizeMap、Flat3Map、LazyMap、LinkedMap、LRUMap、MultiKeyMap、PredicatedMap、SingletonMap和StaticBucketMap类都比较有用。

 类似资料: