Java中的集合介紹
一、基本介紹
1、結構圖
2、新增物件
向集合中新增的員工物件:Clerk
//建立一個員工類
public class Clerk {
private String name;//姓名
private int age;//年齡
private float sal;//工資
public Clerk(String name,int age,float sal)
{
this.name=name;
this.age=age;
this.sal=sal;
}
//及get、set
}
二、List結構的集合
說明:有序,可重複
1、ArrayList類
ArrList實現類:ArrayListDemo
import java.util.ArrayList; public class ArrayListDemo { public static void main(String[] args) { // 定義ArrayList物件 ArrayList al = new ArrayList(); // 顯示大小 System.out.println("al大小:" + al.size()); test1(al);//向al中新增資料 test2(al);//遍歷al中的資料 //test3(al);//刪除al中的資料 } private static void test3(ArrayList al) { // 如何從al中刪除一個物件 al.remove(1); System.out.println("===刪除吳用==="); } private static void test2(ArrayList al) { // 如何訪問al中的物件(資料) // 訪問第一個物件 // Clerk temp=(Clerk)al.get(0); // System.out.println("第一個人的名字是:"+temp.getName()); // 遍歷al所有的物件(資料) for (int i = 0; i < al.size(); i++) { Clerk temp = (Clerk) al.get(i); System.out.println("名字:" + temp.getName()); } } private static void test1(ArrayList al) {//向al中新增資料 // 向all中加入資料(型別是Object) // 建立一個職員 Clerk clerk1 = new Clerk("宋江", 50, 1000); Clerk clerk2 = new Clerk("吳用", 45, 1200); Clerk clerk3 = new Clerk("林沖", 35, 1300); // 將clerk1加入到al中 al.add(clerk1); al.add(clerk2); al.add(clerk3); // 可不可以放入同樣的物件? al.add(clerk1);//可以 // 顯示大小 System.out.println("al大小:" + al.size());//按順序輸出 } }
注意:ArrayList無同步性,執行緒不安全,可以重複新增,按順序
2、LinkedList類
public class LinkedListDemo { static Clerk clerk1=new Clerk("sa01",33,1.2f); static Clerk clerk2=new Clerk("sa02",44,1.2f); static Clerk clerk3=new Clerk("sa03",66,1.2f); public static void main(String[] args) { // 定義LinkedList物件 LinkedList ll=new LinkedList(); // 顯示大小 System.out.println("ll大小:" + ll.size()); test1(ll);//向ll中新增資料 test2(ll);//刪除ll中的資料 } //刪除ll中的資料 private static void test2(LinkedList ll) { //remove表示將某一條資料進行刪除 ll.remove(clerk1);//將ll中的clerk1資料刪除 System.out.println("測試LinkedList集合類中的remove方法"); for(int i=0;i<ll.size();i++){ System.out.println(((Clerk)ll.get(i)).getName()); } ll.removeAll(ll);//清除整個連結串列 System.out.println("測試LinkedList集合類中的remmoveall方法"); for(int i=0;i<ll.size();i++){ System.out.println(((Clerk)ll.get(i)).getName());//表示的是clerk.get方法 } } //向ll中新增資料 private static void test1(LinkedList ll) { //addFirst表示把clerk1載入(連結串列)佇列的最前面 ll.addFirst(clerk1);//addFirst方法是可以插入在陣列之前,新增後:01 ll.addFirst(clerk2);//也可以理解為addFirst方法是後進先出的方法,02,01 //addLast表示把clerk3載入(連結串列)佇列的後面 ll.addLast(clerk3);//02,01,03 System.out.println("測試LinkedList集合類中的addFist及addLast方法"); for(int i=0;i<ll.size();i++){//輸出:02,01,03 System.out.println(((Clerk)ll.get(i)).getName()); } } }
注意:採用連結串列形式,從佇列前面出
3、Vector類
public class VectorDemo {
public static void main(String[] args) {
//Vector的用法
Vector vv=new Vector();
text1(vv);//向vv中新增資料
text2(vv);//遍歷vv中的資料
}
private static void text2(Vector vv) {
//遍歷
for(int i=0;i<vv.size();i++){
Clerk clerk=(Clerk)vv.get(i);
System.out.println(clerk.getName());
}
}
private static void text1(Vector vv) {
Clerk clerk1=new Clerk("1",23,1.2f);
Clerk clerk2=new Clerk("2",55,1.2f);
Clerk clerk3=new Clerk("3",34,1.2f);
vv.add(clerk1);
vv.add(clerk2);
vv.add(clerk3);
vv.add(clerk1);
}
}
注意:執行緒安全具有同步性
4、Stack類
//Stack集合類(棧)的使用方法
public class StackDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
// Stack的用法
Stack stack = new Stack();
Clerk clerk1 = new Clerk("s1", 21, 1.2f);
Clerk clerk2 = new Clerk("s2", 23, 1.2f);
stack.add(clerk1);
stack.add(clerk2);
stack.add(clerk2);
for (int i = 0; i < stack.size(); i++) {
System.out.println(((Clerk) stack.get(i)).getName());
}
}
}
三、Map結構的集合
1、HashMap類
public class HashMapDemo {
public static void main(String[] args) {
//建立HashMap物件
HashMap hm=new HashMap();
test1(hm);//向hm中新增資料
test2(hm);//查詢hm中的資料
}
private static void test2(HashMap hm) {
//如果你要查詢編號是s002
if(hm.containsKey("s002")){//取鍵值containsKey
System.out.println("有該員工");
//如何取出,鍵<key>值
Clerk clerk=(Clerk)hm.get("s002");
System.out.println("名字"+clerk.getName());
}else{
System.out.println("沒該員工");
}
//遍歷HashMap中所有的key和value值
//Iterator迭代
Iterator it=hm.keySet().iterator();
//hasNext返回一個boolean值
while(it.hasNext()){
//如果有下一個取出key值
String key=it.next().toString();
//通過key取出value
Clerk clerk=(Clerk)hm.get(key);
System.out.println("名字:"+clerk.getName());
System.out.println("工資:"+clerk.getSal());
}
}
private static void test1(HashMap hm) {
Clerk clerk1=new Clerk("s001",21,3.4f);
Clerk clerk2=new Clerk("s002",22,5.6f);
Clerk clerk3=new Clerk("s003",23,1.2f);
//將Clerk放入到hm中
//hm.put(null,null);//可以放空值
hm.put("s001", clerk1);
hm.put("s002", clerk2);
hm.put("s002", clerk3);//不允許key重複,所以Clerk3會覆蓋Clerk2
}
}
注意:因為使用雜湊演算法,所以取出所有值時並不是按順序的
2、Hashtable類
public class HashtableDemo {
public static void main(String []args){
Hashtable ht=new Hashtable();//Hashtable與HsahMap在用法上一致
test1(ht);//新增
test2(ht);//遍歷
}
private static void test2(Hashtable ht) {
for(Iterator it=ht.keySet().iterator();it.hasNext();){
String key=it.next().toString();
Clerk clerk=(Clerk)ht.get(key);
System.out.println("名字:"+clerk.getName()+"\t工資:"+clerk.getSal());
}
}
private static void test1(Hashtable ht) {
Clerk clerk4=new Clerk("s101",22,2.2f);
Clerk clerk5=new Clerk("s102",32,1.2f);
Clerk clerk6=new Clerk("s103",32,4.2f);
ht.put("s101", clerk4);
ht.put("s102", clerk5);
ht.put("s103", clerk6);
}
}
注意:Hashtable具有同步性,執行緒安全
3、HashMap和Hashtable的區別
- 歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是java 1.2引進的Map介面的一個實現。
- 同步性:Hashtable是執行緒同步的。這個類中的一些方法保證了Hashtable中的物件是執行緒安全的。而HashMap則是執行緒非同步的,因此HashMap中的物件並不是執行緒安全的。因為同步的要求會影響執行的效率,所以如果你不需要執行緒安全的集合那麼使用HashMap是一個很好的選擇,這樣可以避免由於同步帶來的不必要的效能開銷,從而提高效率。
- 值:HashMap可以讓你將空值作為一個表的條目的key或value但是Hashtable是不能放入空值的(null)
四、Set結構的集合類
1、HashSet類
HashSet是基於HashMap實現的,HashSet底層採用HashMap來儲存所有元素。
public class HashSetDemo {
public static void main(String []args){
HashSet<Clerk> hs=new HashSet<Clerk>();
test1(hs);//向hs中新增資料
test2(hs);//遍歷
}
private static void test2(HashSet<Clerk> hs) {
//轉換陣列o[],遍歷並輸出HashSet中的無素
Object o[]=hs.toArray();
for(int i=0;i<o.length;i++){
System.out.println("姓名:"+((Clerk)o[i]).getName()+"\t年齡:"+((Clerk)o[i]).getAge()+"\t工資:"+((Clerk)o[i]).getSal());
}
}
private static void test1(HashSet<Clerk> hs) {
Clerk clerk1=new Clerk("s001",21,1.2f);
Clerk clerk2=new Clerk("s002",22,1.6f);
Clerk clerk3=new Clerk("s003",23,1.8f);
Clerk clerk4=new Clerk("s001",24,1.2f);
hs.add(clerk1);
hs.add(clerk2);
hs.add(clerk3);
hs.add(clerk4);
hs.add(clerk1);//重複的clerk1,HashSet會自動去除
System.out.println("HashSet_size="+hs.size());
System.out.println();
ArrayList<Clerk> al=new ArrayList<Clerk>();
Clerk clerk5=new Clerk("s004",33,1.0f);
Clerk clerk6=new Clerk("s005",14,2.5f);
al.add(clerk5);
al.add(clerk6);
//al.add(clerk1);
hs.addAll(al);//將al中的值加到hs中,並去除重複的clerk1
System.out.println("HashSet_ArrayList_size="+hs.size());
System.out.println();
}
}
2、TreeSet類
TreeSet集合類是一個有序集合,它的元素按照升序排序,預設是自然順序排列,也就是說TreeSet中的物件元素需要實現Comparable介面。TreeSet與HashSet類一樣沒有get()方法來獲取列表中的元素,所以也只能通過迭代器方法來獲取。 TreeSet是依靠TreeMap來實現的,TreeSet是一個有序集合,它的元素按照升序排列,預設是按照自然順序排列,也就是說TreeSet中的物件元素需要實現Comparable介面
注意:由於TreeMap需要排序,所以需要一個Comparator為鍵值進行大小比較,當然也是用Comparator定位的Comparator可以在建立TreeMap時指定,這時排序時使用Comparator.compare。如果建立時沒有指定Comparator那麼就會使用key.compareTo()方法,這就要求key必須實現Comparable介面。TreeMap是使用Tree資料結構實現的,所以使用compare介面就可以完成定位了。其要操作的物件類如下:
//建立Strudent學生類並實現Comparable與Comparator介面
class Student implements Comparable,Comparator{
private int num;//定義學號
private String name;//定義名字
public Student(int num,String name){
this.num=num;
this.name=name;
}
public int compareTo(Object o){
Student st=(Student)o;
int result;
result=num>st.num?1:(num==st.num?0:-1);//判斷學號是否相同並返回result的值
//如果學號相等,就按姓名排列
/* if(result==0){
return name.compareTo(st.name);
}*/
return result;
}
//實現Comparator介面並實現它的抽象方法
public int compare(Object o1,Object o2){
Student st1 =(Student)o1;
Student st2 =(Student)o2;
return st1.name.compareTo(st2.name);//比較姓名是否相同
}
//重寫toString()方法,因為如果不重寫,打印出來的是16進位制程式碼
public String toString(){
return "num="+num+"; name="+name;
}
public static class StudentComparator implements Comparator{//定義一個靜態StudentComparator類並實現Comparator介面
public int compare(Object o1,Object o2){
Student st1 =(Student)o1;
Student st2 =(Student)o2;
int result;
result=st1.num>st2.num?1:(st1.num==st2.num?0:-1);//判斷學號是否相同進行排序
if(result==0){//如果學號相等 就進行名字排序
result=st1.name.compareTo(st2.name);
}
return result;
}
}
}
那麼TreeSet類的使用如下:
public class TreeSetDemo{
public static void main(String[] args){
//傳遞一個比較器來實現你自己的排序方式
TreeSet tr =new TreeSet(new Student.StudentComparator());
tr.add(new Student(301,"張三"));//將學生資料寫入TreeSet集合類的tr中
tr.add(new Student(201,"李二"));
tr.add(new Student(101,"王五"));
tr.add(new Student(101,"窮一"));
Iterator it=tr.iterator();//迭代器,遍歷
while(it.hasNext()){//判斷是否有下一個元素
System.out.println(it.next());
}
}
}
五、三大集合結構的比較
1、總體
- List按物件進入的順序儲存物件,不做排序和編輯操作。
- Set對每個物件只接受一次,並使用自己內部的排序方法(通常,你只關心某個元素是否屬於Set而不關心它的順序--否則使用List)。
- Map同樣對每個元素儲存一份,但這是基於"鍵"(key)的,Map也有內建的排序,因而不關心元素新增的順序。如果新增元素的順序對程式設計很重要,應該使用LinkedHashSet或者LinkedHashMap。
2、具體
1.List的功能方法
實際上有兩種List:一種是基本的ArrayList其優點在於隨機訪問元素,另一種是更強大的LinkedList它並不是為快速隨機訪問設計的,而是具有一套更通用的方法。
- List:次序是List最重要的特點:它保證維護元素特定的順序。List為Collection添加了許多方法,使得能夠向List中間插入與移除元素(這隻推薦LinkedList使用)一個List可以生成Listlterator,使用它可以從兩個方向遍歷List,也可以從List中間插入和移除元素。
- ArrayList:由陣列實現的List。允許對元素進行快速隨機訪問,但是向List中間插入與移除元素的速率很慢。Listlterator只應該用來由後向前遍歷ArrayList。而不是用來插入和移除元素。因為那比LinkedList開銷要大很多。
- LinkedList:對順序訪問進行了優化,向List中間插入與刪除的開銷並不大。隨機訪問則相對較慢。(使用ArrayList代替)還具有下列方法:addFirst(),addLast(),getFirst(),getLast(),removeFirst()和removeLast()這些方法(沒有在任何介面或基類中定義過)使得LinkedList可以當作堆疊、佇列和雙向佇列使用。
2.Set的功能方法
Set具有與Collection完全一樣的介面,因此沒有任何額外的功能,不象前面有兩個不同的List。實際上Set就是Collection,只是行為不同。(這是繼承與多型思想的典型應用:表現不同的行為。)Set不儲存重複的元素(至於如何判斷元素相同則較為負責)
- Set:存入Set的每個元素都必須是唯一的,因為Set不儲存重複元素。加入Set的元素必需定義equals()方法以確保物件的唯一性。Set與Collection有完全一樣的介面。Set介面不保證維護元素的次序。
- HashSet:為快速查詢設計的Set。存入HashSet的物件必須定義hashCode()。
- TreeSet:儲存次序的Set,底層為樹結構。使用它可以從Set中提取有序的序列。
- LinkedHashSet:具有HashSet的查詢速度,且內部使用連結串列維護元素的順序(插入的次序)。於是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。
3.Map的功能方法
方法put(Object key,Object value)新增一個"值"(想要得東西)和與"值"相關的"鍵"(key)(使用它來查詢)。方法get(Object key)返回與給定"鍵"相關聯的"值"。可以用containsKey()和containsValue()測試Map中是否包含某個"鍵"或"值"。標準的java類庫中包含了幾種不同的Map:HashMap,TreeMap,LinkedHashMap,WeakHashMap,ldentityHashMap。它們都有同樣的基本介面Map,但是行為、效率、排序策略、儲存物件的生命週期和判定"鍵"等價的策略等各不相同。
執行效率是Map的一個大問題。看看get()要做哪些事,就會明白為什麼在ArrayList中搜索"鍵"是相當慢的。這正是HashMap提高速度的地方。HashMap使用了特殊的值,稱為"雜湊碼"(hash code),來取代對鍵的緩慢搜尋。"雜湊碼"是"相對唯一"用以代表物件的int值,它是通過將該物件的某些資訊進行轉換而生成的。所有java物件都能產生雜湊碼,因為hashCode()是定義在基類Object中的方法。HashMap就是使用物件的hashCode()進行快速查詢的。此方法能夠顯著提高效能。
- Map:維護"鍵值對"的關聯性,使你可通過"鍵"查詢"值"
- HashMap:Map基於散列表的實現。插入和查詢"鍵值對"的開銷是固定的。可以通過構造器設定容量capacity和負載因子load factor,以調整容器的效能。
- LinkedHashMap:類似於HashMap,但是迭代遍歷它時,取得"鍵值對"的順序是其插入次序,或者是最近最少使(LRU)的次序。只能HashMap慢一點。而在迭代訪問時發而更快,因為它使用鍵表維護內部次序。
- TreeMap:基於紅黑樹資料結果的實現。檢視"鍵"或"鍵值對"時,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特點在於,你得到的結果是經過排序的。TreeMap是唯一的帶有subMap()方法的Map,它可以返回一個子樹。
- WeakHashMap:旨鍵(weak key)Map,Map中使用的物件也被允許釋放:這是為解決特殊問題設計的。如果沒有map之外的引用指向某個"鍵",則此"鍵"可以被垃圾收集器回收。
- ldentifyHashMap:使用==代替equals()對"鍵"作比較的hash map。專為解決特殊問題而設計。
六、其他雜項
1、增刪方法詳解
java.util包中包含了一系列重要的集合類,集合類的根介面Collection。Collection介面是所有集合類的根型別。它的一個主要的介面方法是:
boolean add(Object c)//新增資料
add()方法將新增一個新元素。注意這個方法會返回一個boolean,但是返回值不是表示新增成功與否。Collection規定:如果一個集合拒絕新增這個元素,無論任何原因,都必須丟擲異常。這個返回值表示的意義是add()方法執行後,集合的內容是否改變了(就是元素有無數量,位置等變化),這是由具體類實現的。即:如果方法出錯,總會丟擲異常;返回值僅僅表示該方法執行後這個Collection的內容有無變化。類似還有:
boolean addall(Collection c);//新增所有資料
boolean remove(Object o);//刪除資料
boolean removeall(Collection c);//刪除所有資料
boolean remainall(Collection c);//保持所有資料
Object[]toArray()方法很簡單,把集合轉換成陣列返回。Object[]toArray(Object[] a)方法就有點複雜了,首先,返回的Object[]仍然是把集合的所有元素變成陣列,但是型別和引數a的型別是相同的。如:
String[] o=(String)c.toArray(new String[0]);//得到的o實際型別是String[]陣列
其次,如果引數a的大小裝不下集合的所有元素,返回的將是一個新的陣列。如果引數a的大小能裝下集合的所有元素,則返回的還是a,但a的內容用集合的元素來填充。尤其要注意的是,如果a的大小比集合元素的個數還多,a後面的部分全部被置為null(空)。
2、迭代器的使用
Iterator模式 是用於遍歷集合類的標準訪問方法。它可以把訪問邏輯從不同型別的集合類中抽象出來,從而避免向客戶端暴露集合的內部結構。例如,如果沒有使用Iterator,遍歷一個數組的方法是使用索引:
for(int i=0;i<array.size();i++)
{..get(i)...}
而訪問一個連結串列(LinkedList)又必須使用while迴圈:
while((e=e.next())!=null)
{...e.data()...}
以上兩種方法客戶端都必須事先知道集合的內部結構,訪問程式碼和集合本身是緊耦合,無法將訪問邏輯從集合類和客戶端程式碼中分離出來,每一種集合對應一種遍歷方法,客戶端程式碼無法複用。更恐怖的是,如果以後需要把ArrayList更換為LinkedList,則原來的客戶端程式碼必須全部重寫。 為解決以上問題,Iterator模式總是用同一種邏輯來遍歷集合:
for(Iterator it=c.iterater();it.hasNext();){ ...}
奧祕在於客戶端自身不維護遍歷集合的"指標",所有的內部狀態(如當前元素位置,是否有下一個元素)都由Iterator來維護,而這個Iterator由集合類通過工廠方法生成,因此,它知道如何遍歷整個集合。客戶端從不直接和集合類打交道,它總是控制Iterator,向它傳送"向前","向後","取當前元素"的命令,就可以間接遍歷整個集合。首先看看java.util.Iterator介面的定義:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
依賴前兩個方法就能完成遍歷,典型的程式碼如下:
for(Iterator it=c.iterator();it.hasNext();){
Object o=it.next();
// 對o的操作...
}
每一種集合類返回的Iterator具體型別可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree 可能返回TreeIterator,但是它們都實現了Iterator介面,因此,客戶端不關心到底是哪種Iterator,它只需要獲得這個 Iterator介面即可,這就是面向物件的威力。
要確保遍歷過程順利完成,必須保證遍歷過程中不更改集合的內容(Iterator的remove()方法除外),因此,確保遍歷可靠的原則是隻在一個執行緒中使用這個集合,或者在多執行緒中對遍歷程式碼進行同步。
Iterator示例:
Collection c=new ArrayList();
c.add("abc");
c.add("xyz");
for(Iterator it:c){
String s=(String)it.next();
System.out.println(s);
}
如果你把第一行程式碼的ArrayList換成LinkedList或Vector,剩下的程式碼不用改動一行就能編譯,而且功能不變,這就是針對抽象程式設計的原則:對具體類的依賴性最小。
3、佇列(Queue)的介紹
Queue介面與List、Set同一級別,都是繼承了Collection介面。LinkedList實現了Queue介面。Queue介面窄化了對LinkedList的方法的訪問許可權(即在方法中的引數型別如果是Queue時,就完全只能訪問Queue介面所定義的方法了,而不能直接訪問 LinkedList的非Queue的方法),以使得只有恰當的方法才可以使用。BlockingQueue繼承了Queue介面。
佇列是一種資料結構。它有兩個基本操作:在佇列尾部加人一個元素,和從佇列頭部移除一個元素。就是說,佇列以一種先進先出的方式管理資料,如果你試圖向一個已經滿了的阻塞佇列中新增一個元素或者是從一個空的阻塞佇列中移除一個元索,將導致執行緒阻塞。
在多執行緒進行合作時,阻塞佇列是很有用的工具。工作者執行緒可以定期地把中間結果存到阻塞佇列中而其他工作者線執行緒把中間結果取出並在將來修改它們。佇列會自動平衡負載。如果第一個執行緒集執行得比第二個慢,則第二個執行緒集在等待結果時就會阻塞。如果第一個執行緒集執行得快,那麼它將等待第二個執行緒集趕上來。
阻塞佇列的操作可以根據它們的響應方式分為以下三類:add、remove和element操作在你試圖為一個已滿的佇列增加元素或從空佇列取得元素時 丟擲異常。當然,在多執行緒程式中,佇列在任何時間都可能變成滿的或空的,所以你可能想使用offer、poll、peek方法。這些方法在無法完成任務時 只是給出一個出錯示而不會丟擲異常。
注意:poll和peek方法出錯進返回null。因此,向佇列中插入null值是不合法的。
其中佇列的方法有:
add | 增加一個元素 | 如果佇列已滿,則丟擲一個IIIegaISlabEepeplian異常 |
remove | 移除並返回佇列頭部的元素 | 如果佇列為空,則丟擲一個NoSuchElementException異常 |
element | 返回佇列頭部的元素 | 如果佇列為空,則丟擲一個NoSuchElementException異常 |
offer | 新增一個元素並返回true | 如果佇列已滿,則返回false |
poll | 移除並返問佇列頭部的元素 | 如果佇列為空,則返回null |
peek | 返回佇列頭部的元素 | 如果佇列為空,則返回null |
put | 新增一個元素 | 如果佇列滿,則阻塞 |
take | 移除並返回佇列頭部的元素 | 如果佇列為空,則阻塞 |
注意:remove、element、offer 、poll、peek 其實是屬於Queue介面。 這些方法的區別有:
- offer,add區別:一些佇列有大小限制,因此如果想在一個滿的佇列中加入一個新項,多出的項就會被拒絕。這時新的 offer 方法就可以起作用了。它不是對呼叫 add() 方法丟擲一個 unchecked 異常,而只是得到由 offer() 返回的 false。
- poll,remove區別:remove()和poll()方法都是從佇列中刪除第一個元素(head)。remove()的行為與Collection 介面的版本相似,但是新的 poll()方法在用空集合呼叫時不是丟擲異常,只是返回null。因此新的方法更適合容易出現異常條件的情況。
- peek,element區別:element()和peek()用於在佇列的頭部查詢元素。與 remove()方法類似,在佇列為空時,element()丟擲一個異常,而peek()返回null。
五個佇列所提供的各有不同:
- ArrayBlockingQueue :一個由陣列支援的有界佇列。基於陣列的阻塞迴圈佇列,先進先出原則對元素進行排序。
- LinkedBlockingQueue:一個由連結節點支援的可選有界佇列。基於連結串列的佇列,先進先出排序元素。
- PriorityBlockingQueue:一個由優先順序堆支援的無界優先順序佇列。PriorityBlockingQueue是對PriorityQueue的再次包裝,是基於堆資料結構的,而PriorityQueue是沒有容量限制的,與ArrayList一樣,所以在優先阻塞佇列上put時是不會受阻的。但是由於資源被耗盡,所以試圖執行新增操作可能會導致OutOfMemoryError),但是如果佇列為空,那麼取元素的操作take就會阻塞,所以它的檢索操作take是受阻的。另外,往入該佇列中的元素要具有比較能力。
- DelayQueue:一個由優先順序堆支援的、基於時間的排程佇列。(基於PriorityQueue來實現的)是一個存放Delayed 元素的無界阻塞佇列,只有在延遲期滿時才能從中提取元素。該佇列的頭部是延遲期滿後儲存時間最長的 Delayed 元素。如果延遲都還沒有期滿,則佇列沒有頭部,並且poll將返回null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於或等於零的值時,則出現期滿,poll就以移除這個元素了。此佇列不允許使用null元素。
- SynchronousQueue:一個利用 BlockingQueue介面的簡單聚集(rendezvous)機制。SynchronousQueue 類是最簡單的。它沒有內部容量。它就像執行緒之間的手遞手機制。在佇列中加入一個元素的生產者會等待另一個執行緒的消費者。當這個消費者出現時,這個元素就直接在消費者和生產者之間傳遞,永遠不會加入到阻塞佇列中。
注意:Queue佇列是不能直接例項化的。在java程式設計中,Queue的實現都是用LinkedList。如:
Queue qe=new LinkedList();
注意:此實現不是同步的。如果多個執行緒同時訪問一個連結列表,而其中至少一個執行緒結構上修改了該列表,則它必須保質外部同步。(結構修改指新增或刪除一個或多個元素的任何操作;僅設定元素的值不是結構修改。)這一般通過對自然封裝該列表的物件進行同步操作來完成。