天天看點

java 7 collection 詳解(二)

    Queue提供了隊列的實作,除了基本的Collection操作外,隊列還提供其他的插入、提取和檢查操作。隊列通常(除優先級隊列、LIFO隊列)以 FIFO(先進先出)的方式排序各個元素。Queue接口代碼如下:

    每一個Queue方法都提供了兩種形式:一種抛出異常(操作失敗時),另一種傳回一個特殊值(null 或 false,具體取決于操作)。插入操作的後一種形式是用于專門為有容量限制的 Queue 實作設計的;在大多數實作中,插入操作不會失敗。詳解如下表:

<b>操作類型</b>

<b>抛出異常</b>

<b>傳回特殊值</b>

插入

add(e)

offer(e)

删除

remove()

poll()

檢視

element()

peek()

    add和offer(e)可向隊列裡插入一個元素,插入失敗事add抛出IllegalStateException,offer(e)傳回false;remove和poll可移除可傳回隊列的頭部元素,如果隊列為空時,remove抛出NoSuchElementException,poll傳回null;element和peek可以檢視隊列的頭部元素(不移除),如果隊列為空時,element抛出NoSuchElementException,peek傳回null。

    即使Queue的實作允許插入null元素,也不要往Queue隊列裡插入null。因為 null 也用作 poll 方法的一個特殊傳回值,表明隊列不包含元素。

    這裡給出一個計時器的Demo,來示範Queue的FIFO特性:

    以上實作了一個十秒鐘的倒計時,當然了對倒計時器可以有着更好的實作,這裡隻是為了更好示範Queue FIFO的性質。同樣地,可以看一下優先級隊列的性質。PriorityQueue,是一個基于優先級堆的無界優先級隊列,其元素是按照其自然順序排列,或者根據構造時提供的Comparator進行排序。PriorityQueue不允許使用 <code>null</code> 元素,依靠自然順序的PriorityQueue還不允許插入不可比較的對象(會抛出<code>ClassCastException</code>)。 Demo:PriorityQueueTest,示範了優先級隊列的性質:

    注意的,Queue 接口并未定義阻塞隊列的方法,而這在并發程式設計中是很常見的。BlockingQueue 接口定義了那些等待元素出現或等待隊列中有可用空間的方法,這些方法擴充了此接口。 

    BlockingQueue繼承了Queue接口,在Queue的基礎上增加了兩個操作:(1)将指定元素插入此隊列中,将等待可用的空間(如果有必要);(2)擷取并移除此隊列的頭部,在元素變得可用之前一直等待(如果有必要)。 方法如下表:

抛出異常

特殊值

阻塞

逾時

<b>插入</b>

<a>add(e)</a>

<a>offer(e)</a>

<a>put(e)</a>

<a>offer(e, time, unit)</a>

<b>移除</b>

<a>remove()</a>

<a>poll()</a>

<a>take()</a>

<a>poll(time, unit)</a>

<b>檢查</b>

<a>element()</a>

<a>peek()</a>

不可用

    在此已經涉及并發程式設計了,例如我們可以使用BlockingQueue來控制連接配接池的連接配接,如果連接配接池已滿,新來的連接配接則需要等待,過了一定的時間,可以移除部分連接配接,這些将會在java并發裡談到,有興趣的可以了解一下java的并發程式設計。

    一個Map就是将鍵映射到值得對象。一個映射裡不能包含相同的Key,同時一個Key最多映射到一個值。這個概念有點像數學裡的函數定義。Map接口代碼如下:

     java提供了三種常用的Map實作:HashMap, TreeMap, 和LinkedHashMap. 其機制與HashSet、TreeSet和LinkedHashSet相似,詳情可了解上一節的Set接口的内容。同樣地,從java 2開始,HashTable改進為Map的一種實作。

    Map的基本操作有put、get、containsKey、containsValue、size和isEmpty。以Demo Frequency.java示範Map的基本操作,在這個Demo裡,我們去計算一段話裡各個單詞出現的次數。

    與Set類似,如果需要以自然順序輸出map的鍵值對,可以使用TreeMap實作。

    Map&lt;String, Integer&gt; map = new TreeMap&lt;&gt;();

    同樣地,如果想按照插入的順序輸出map的鍵值對,可以使用LinkedHashMap。

    Map&lt;String, Integer&gt; map = new LinkedHashMap&lt;&gt;();

    在此,也需要指出的就是,所有Map的實作,都需要提供一個空的構造函數,另外是有一個map參數的構造函數,帶map參數的構造函數可以允許複制一個map。其作用原理與Collection類似。

    Map&lt;K, V&gt; copy = new HashMap&lt;K, V&gt;(m);

    clear()方法可以清空Map裡的所有鍵值對;putall()方法可以将另一個map裡的鍵值對添加進來,類似于Collection裡的addAll()方法。類似地,我們可以利用putAll()方法将兩個Map合并成一個新的Map,如下所示:

    Collection視圖方法允許把Map當作一個Collection來處理。Map 接口提供三種了Collection 視圖,允許以鍵集、值集或鍵-值映射關系集的形式檢視某個映射的内容,其方法如下:

<code>keySet</code> — 由Key組成Set視圖

<code>values</code> — 由value組成Collection視圖,但又與Set視圖有差別,因為一個value可以映射到多個Key上(即可能有重複的元素)

<code>entrySet</code> — 由key-value組成的Set視圖。在Map接口裡内嵌裡一個小接口Map.Entry

    周遊Collection視圖的方法,類似的可以使用foreach方法或使用Iterator接口,當中Key視圖與value視圖的周遊操作類似,這裡以key視圖為例:

    key-value視圖的周遊其實也很是類似,隻不過這次用的是Map,Entry,

    在這三種視圖裡,都可以是用Iterator#remove()方法移除Map裡的元素.對于key-value視圖,疊代時還可以Map.Entry#setValue.

    Collection視圖允許使用各種移除元素的方法,包括remove, removeAll, retainAll, 和 clear 方法,還包括Iterator的remove方法.可注意的是,在任何情況下,Collection視圖都不支援添加元素的方法.添加元素對于key視圖和value視圖沒有任何意思,對key-value視圖也沒有必要,因為Map的put和putAll方法已經提供了添加元素的方法.

    Collection視圖的應用,往往就是各種Map批量操作的應用(<code>containsAll</code>, <code>removeAll</code>, 和<code>retainAll).</code>

<code>    首先了解一下,如何去判斷m2是不是m1的子Map,即判斷m1是否包含了m2所有的key,</code>

    類似的,可以判斷一下,m1與m2是否相等,即key的所有值都一樣:

    通常,我們會遇到這麼一種情況,去判斷Map對象是否有指定的值構成,現在我們假設有兩個Set,當中一個Set包含裡必須有的值,另外一個Set則包含裡可能的值(可能的值包含了必須有的值),現在我們來判斷一下,Map的屬性值是否合法(即是否全包好了必須的值,其他值又是否都在可能的值去到):

    在validate裡隻是簡單的輸出對應的資訊,實際程式設計時來合理添加具體邏輯。類似的,看一下其他應用:如求兩個Map的共同元素(即交集),可以這樣實作:

   那又如何删除兩個Map的相同元素呢(差集)??

   m1.entrySet().removeAll(m2.entrySet());

   以上三種方法都可以删除map裡相同的元素,可也有一定的差別。entrySet移除的是key-value一緻的鍵值對(唯一),keySet移除的是key相同的值(唯一),values移除的是值相同的鍵值對(可能有多個,因為一個value,可以對應多個key)。

   到現在為止所說的關于map的方法,都是無損的,因為這些方法都沒有嘗試去修改Map裡的值。如果需要修改map的key值,注意不能原map裡的其他key相同(map裡包含相同的key),如果修改後的key值與某一key相同,會引發異常。

   現在進一步來學一下map的應用,可以設想一下,如果在map批量操作裡,同時操作裡key和value視圖,會發生什麼情況或者說有什麼作用??舉個例子:假設有一個Map對象managers,以員工-上司的鍵值形式存儲(這裡假設員工、上司都是Employee對象,具體實作可根據實際情況來設計),現在需要找出沒有配置設定到的經上司的員工,應該如何去找呢??

   接着看一下,如何去删除(解雇)某個上司(經理)下的所有員工呢??

   附:工廠方法Collections.singleton()在前面談過,可以傳回隻包含某個對象的Set。

   如果需要找出一線員工(即最低層的員工,注意上司還可以有上司的上司等)??

   為了加深對上面邏輯的了解,可以看一下一個簡單的Demo:MapTest.java

    當中A輸出:{3=2, 2=1}。注:此處“=”沒有任何的意義,隻是表示鍵值對的形式。

    B輸出:{2=1}

    C輸出:{3=2}

    D輸出:{3=2}

   三種Collection視圖方法,在實際應用的時候,隻需要稍加推到可以得到多種靈活的變化。

本文轉自peiquan 51CTO部落格,原文連結:http://blog.51cto.com/peiquan/1290180