1. 程式人生 > 實用技巧 >Java集合(三)—List和Queue集合

Java集合(三)—List和Queue集合

公眾號: 菜雞幹Java 歡迎關注

目錄

Java集合—List集合

與Set集合不同,List集合是有序,可重複的,而且預設以新增順序設定索引。List子介面是繼承了Collection介面,則可以使用其中的方法。

特別的是List增加了根據索引插入、替換、刪除集合元素的方法,此外,Java8為List介面添加了兩個預設方法:

  • void replaceAll():根據指定規則重新設定List集合的所有元素
  • void sort(Comparator c):根據引數對List集合的元素排序
List books = new ArrayList();
books.add(new String("ledon"));
books.add(new String("Android"));
books.sort((o1,o2)->((String)o1).length()-((String)o2).length());
//字串將由短到長排序
System.out.println(books);
books.replaceAll(e->((String)e).length());
System.out.println(e);//[5,7]

值得注意的是List判斷兩個物件相等,只要通過equals方法比較返回true即可,不像Set集合,還需要判斷雜湊值是否相等來避免重複。

刪除元素時,List會呼叫物件的equals方法依次與集合元素比較,如果返回true,則會刪除該元素。如果重寫了equals方法,使它總是返回true,則List總會刪除第一個元素。在使用set(index,object)方法時,index不能超過集合的長度,也不能改變長度。

List不僅有iterator()方法,還有listIterator()方法,該方法返回一個ListIterator物件,ListIterator介面繼承了Iterator介面,提供了專門的方法操作List

,增加了如下方法(類似Iterator的方法):

  • boolean hasPrevious():返回該集合是否還有上一個元素
  • Object previous():返回上一個元素
  • void add(Object o):在指定位置插入一個元素

不難發現該介面還能向前迭代,不止能刪除元素,並且還能通過add()方法,新增元素。

ArrayList和Vector

它們兩個封裝了 一個動態的Object[ ]陣列,允許再分配。ArrayListVector物件使用initialCapacity引數來設定陣列的長度,當超出陣列容量時,initialCapacity會自動增加,可使用ensureCapacity(int minCapacity)方法一次性增加initialCapacity。如果事先知道元素的個數,可指定初始大小;如果沒有指定初始容量,預設為10。

ArrayListVector提供了兩個方法重新分配Object[]陣列:

  • void ensureCapacity(int minCapacity):將ArrayListVector集合的Object[]陣列長度增加到大於或等於minCapacity值
  • void trimToSize():調整ArrayListVector的陣列長度為當前元素個數,減少佔用空間

ArrayListVector的用法幾乎完全相同,Vector也是實現了List介面,從JDK1.0就有了,很古老!此外,ArrayList是執行緒不安全的,原理一樣;但Vector是執行緒安全的,即無需保證執行緒的同步性,因而Vector的效能比ArrayList低。但是還是用ArrayList更多,要想執行緒安全,也可以把ArrayList變成執行緒安全。

Stack類(Vector的子類)

翻譯過來就是“棧”,模擬進棧push,出棧pop等操作。作為集合的一種,它也是儲存物件(Object)的,有如下方法:

  • Object peek():返回棧頂元素,但並不彈出該元素,元素還會在棧內
  • Object pop():返回棧頂元素,並彈出棧
  • void push(Object item):推元素進棧

Stack繼承了Vector,所以它也非常古老,執行緒安全、效能較差。後面還會介紹一種“棧”結構——ArrayDeque,它不僅實現了List介面,還實現了Deque介面,如果需要棧結構,可以使用它而不是Stack

固定長度的List

有一種運算元組的工具類Arrays,該工具類提供了asList()方法,該方法把一個數組或指定個數的物件換成一個List集合,這個集合不是以上所介紹的集合類的例項,不是ArrayList的,不是Vector的,而是Arrays的內部類ArrayList的例項。Arrays.ArrayList是一個固定長度的List集合,不允許新增、刪除操作,只能遍歷訪問,否則程式將出現UnsupportedOperationException異常。

Java集合-Queue集合

Queue介面中定義瞭如下的方法:

  • void add(Object e):新增元素到隊尾
  • boolean offer(Object e):將指定元素加入佇列的尾部,成功返回true
  • Object element():獲取佇列頭部的元素,但不是刪除該元素
  • Object remove():獲取頭部元素,並刪除該元素
  • Object peek():獲取佇列頭部的元素,但不是刪除,如果為空返回null
  • Object poll():獲取並刪除頭部元素,為空,返回null

Queue有一個PriorityQueue實現類,除此外還有一個Deque介面,代表雙端佇列,即兩端可以新增刪除元素。其實現類為ArrayDequeLinkedList兩個實現類。

PriorityQueue類

PriorityQueue並不是一個標準的佇列,其儲存佇列的順序是重新排序了的(按元素的大小),顯然不符合佇列的規則。如果呼叫poll方法,可以看到元素從小到大移出佇列。另外需要注意的是,PriorityQueue不允許插入null元素!

它的排序有兩種,自然排序、定製排序,排序規則與TreeSet類似:

  • 自然排序:自然排序時,元素必須實現了Comparable介面,而且是同一類的例項。
  • 定製排序:建立佇列時,傳入一個Comparator物件,該物件負責排序,但是不要求元素實現Comparable介面

Deque介面與ArrayDeque

Deque介面是Queue的子介面,允許對佇列兩端進行操作,同時,還可以當作“棧”來使用,因為它還有poppush方法。典型的實現類是ArrayDeque,一個基於陣列的雙端佇列,在建立Deque時,同樣可以指定一個numElement元素個數引數,指定Object[ ]陣列的長度;如果不指定,則預設長度為16。

ArrayListArrayDeque的實現原理差不多,底層採用一個動態的、可再分配的陣列實現,初始化可指定初始長度等,當元素個數超出容量時,系統會重新分配一個Object[]陣列儲存元素。

LinkedList類

LinkedList實現了List介面,是List集合,還實現了Deque介面,可以當雙端佇列使用,還能當"棧"使用。 但它的實現機制與ArrayListArrayDeque的不一樣,它兩是用陣列實現,而LinkedList是以連結串列的形式來儲存元素,隨機訪問效能較差,但插入、刪除操作比較溜!

線性表效能分析

一般來說,陣列由一塊連續的記憶體來儲存資料,所以陣列隨機訪問效能好,類似的,以陣列為底層實現的類,隨機訪問效能都比較好;而連結串列的插入、刪除操作效能好。綜合來講,還是用ArrayList比較妥。

  • 如果需要遍歷:對於ArrayListVector集合,使用隨機訪問方法遍歷即可;對於LinkedList集合,採用Iterator迭代器遍歷比較好。

  • 如果經常要執行插入、刪除操作,可以使用LinkedList集合,而使用以陣列為底層的線性表要重新分配內部陣列大小,效能較差。

  • 如果有多個執行緒同時訪問,可以使用工具類包裝成執行緒安全的集合。