Java 集合體系與List

一、集合體系

1)Collection接口

在Java類庫中,Collection是集合最基本的接口。Collection定義了一系列集合常用操作(獲取迭代器、添加、刪除、包含、轉化數組、判斷是否爲空、大小)以及default默認方法接口 ( 大部分與流相關( 除removeIf,其用來刪除滿足符合某個條件的元素 ) )。AbstractCollection實現了部分Collection方法。

boolean add(E e)
//確保此集合包含指定的元素(可選操作)。

boolean addAll(Collection<? extends E> c)
//將指定集合中的所有元素添加到此集合(可選操作)。

void clear()
//從此集合中刪除所有元素(可選操作)。

boolean contains(Object o)
//如果此集合包含指定的元素,則返回 true 。

boolean containsAll(Collection<?> c)
//如果此集合包含指定 集合中的所有元素,則返回true。

boolean equals(Object o)
//將指定的對象與此集合進行比較以獲得相等性。

int hashCode()
//返回此集合的哈希碼值。

boolean isEmpty()
//如果此集合不包含元素,則返回 true。

Iterator<E> iterator()
//返回此集合中的元素的迭代器。

default Stream<E> parallelStream()
//返回可能並行的 Stream與此集合作爲其來源。

boolean remove(Object o)
//從該集合中刪除指定元素的單個實例(如果存在)(可選操作)。

boolean removeAll(Collection<?> c)
//刪除指定集合中包含的所有此集合的元素(可選操作)。

default boolean removeIf(Predicate<? super E> filter)
//刪除滿足給定謂詞的此集合的所有元素。例:
  ArrayList<String> list = new ArrayList<>();
  list.add("張三");
  list.add("李四");
  list.add("王二");
  list.add("李麻子");
  list.add("李三");
  list.removeIf(obj->obj.contains("李"));

boolean retainAll(Collection<?> c)
//僅保留此集合中包含在指定集合中的元素(可選操作)。

int size()
//返回此集合中的元素數。

default Spliterator<E> spliterator()
//創建一個Spliterator在這個集合中的元素。

default Stream<E> stream()
//返回以此集合作爲源的順序 Stream 。

Object[] toArray()
//返回一個包含此集合中所有元素的數組。

<T> T[] toArray(T[] a)
//返回包含此集合中所有元素的數組; 返回的數組的運行時類型是指定數組的運行時類型。

2)Iterator接口

boolean hasNext()
//如果迭代具有更多的元素,則返回true 。 (換句話說,如果next()返回一個元素而不是拋出一個異常,則返回true )
//結果 true如果迭代有更多的元素

E next()
//返回迭代中的下一個元素。
//結果 迭代中的下一個元素
//異常 NoSuchElementException - 如果迭代沒有更多的元素

default void remove()
//從底層集合中刪除此迭代器返回的最後一個元素(可選操作)。 此方法只能調用一次next() 。 如果底層集合在迭代過程中以任何方式進行修改而不是通過調用此方法,則迭代器的行爲是未指定的。
//實現要求: 默認的實現拋出的一個實例UnsupportedOperationException並執行其他操作。
//異常 UnsupportedOperationException -如果 remove操作不會被這個迭代器支持
//     IllegalStateException - 如果 next方法尚未被調用,或者 remove方法在上次調用 next方法之後已經被調用

default void forEachRemaining(Consumer<? super E> action)
//對每個剩餘元素執行給定的操作,直到所有元素都被處理或動作引發異常。 如果指定了該順序,則按迭代的順序執行操作。 動作拋出的異常被轉發給呼叫者。
//實現要求: 默認實現的行爲如下: while (hasNext()) action.accept(next());  
//參數 action - 要爲每個元素執行的操作
//異常 NullPointerException - 如果指定的動作爲空
//從以下版本開始: 1.8

重點看一下 forEachRemaining:

用法:forEachRemaining(element->對element的操作  element)

在沒有引入lambda之前,集合支持兩種遍歷方式:1、for/while獲取迭代器遍歷。2、使用for-each遍歷(Collection實現了Iterable,其規定必須有一個迭代器。所以對任何集合都可以使用for-each遍歷)。這兩種方法的共同特點都是要使用循環。到了Java8,其引入了forEachRemaining遍歷方法。這個方法允許不使用循環遍歷集合:

ArrayList<String> list = new ArrayList<>();
list.add("test1");
list.add("test2");
Iterator<String> iter = list.iterator();
iter.forEachRemaining(e-> System.out.println(e));

 

二、list體系及其迭代器

1)Java中的鏈式結構

Java中的鏈表都是雙向循環鏈表,其可以從鏈表兩頭開始遍歷。如果對LinkedList進行索引訪問(不推薦,下面會講到),若訪問的座標大於length/2,則從鏈表尾端向前遍歷。

2)ArrayList與LinkedList(兩者都不是同步的,有線程安全問題)

ArrayList:實現結構爲循環數組。數組相比鏈表最大的特點就是可以按索引下標訪問(隨機訪問)。但是數組如果要在中間加入/刪除元素會導致前/後方元素集體移動,非常耗時間。

LinkedList:實現結構爲雙向鏈表。鏈式結構相比數組最大的特點就是在鏈表中間插入/刪除元素只需要修改引用即可,不需要移動前/後方所有元素。缺點是按索引訪問會非常慢,因爲要從頭/尾遍歷挨個尋找元素。

綜上描述,可以歸納出以下幾點:

(1)當要按索引訪問時,使用ArrayList。

(2)當要對錶中添加/刪除元素時,使用LinkedList。

(3)ArrayList一般用於查詢,LinkedList用於修改。

3)lterator與listIterator

listIterator接口繼承自lterator接口:

void add(E e)
//將指定的元素插入列表(可選操作)。

boolean hasNext()
//返回 true如果遍歷正向列表,列表迭代器有多個元素。

boolean hasPrevious()
//返回 true如果遍歷反向列表,列表迭代器有多個元素。

E next()
//返回列表中的下一個元素,並且前進光標位置。

int nextIndex()
//返回隨後調用 next()返回的元素的索引。

E previous()
//返回列表中的上一個元素,並向後移動光標位置。

int previousIndex()
//返回由後續調用 previous()返回的元素的索引。

void remove()
//從列表中刪除由 next()或 previous()返回的最後一個元素(可選操作)。

void set(E e)
//用指定的元素替換由 next()或 previous()返回的最後一個元素(可選操作)。

(1)listIterator(ArrayList與LinkedList通用)

上方說過,Java中的鏈表爲雙鏈表,因此可以進行向前/後遍歷。listIterator與普通迭代器不同的是其提供了可以向前遍歷、獲取前方元素以及可以在元素中間插入元素的操作。

(2)迭代器的操作

我們使用 | 代表迭代器說明其工作原理

|ABC  ——> iter.next() ——> A|BC ——> 返回A(越過A)——>iter.next() ——> AB|C ——> iter.remove() ——> A|C(越過B) 

在使用next()方法後,迭代器越過了元素A,因此返回元素A;後邊越過B,因此刪除的是B。由此可見,迭代器只會對向前/後越過的元素進行操作。

(3)同步安全性(重點)

ArrayList與LinkedList是線程不安全的!

1、集合可以跟蹤改寫操作(添加、刪除元素)的次數,迭代器也會維護一個自己進行改寫操作次數的計數器。當兩個計數數值不相等時便會拋出ConcurrentModificationException併發異常。例如在遍歷list的時候使用list自己的刪除方法刪除了元素(list的計數器改變)但是沒有使用迭代器刪除元素(迭代器的計數器不改變),兩者計數數值不一致便會拋出ConcurrentModificationException異常。但是如果使用了迭代器的remove()方法(迭代器計數數值加一)刪除了list(list計數數值加一)的元素,兩者相等,操作成功。

2、若同一個集合有兩個迭代器,A迭代器發現B迭代器對集合進行了修改,則A就會拋出ConcurrentModificationException併發異常。

4)Vector

Vector的所有方法都是同步的,但是爲了實現同步會浪費大量的時間。他可以使得兩個線程安全的訪問Vector。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章