Apache Commons Collections 標籤: collectionsapachehashmapcommandobjectjavadoc 2012-05-09 10:13 1070人閱讀 評論(0) 收藏 舉報 分類: Java編程(74)
目錄(?)[+] 原文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(Str