1. 程式人生 > 其它 >Java 集合框架1:Collection

Java 集合框架1:Collection

目錄

集合框架

1.概述

集合 collection ,也稱為 container 容器,一個將多個物件組合成一個單元的物件。集合用於儲存、返回、操作以及聚合。集合框架是一個統一表示和管理集合的框架。它減少不必要的程式設計工作,提升程式的速度和質量、互操作性,減少重複設計。

介面、實現、聚合操作和演算法共同組成了 Java 的集合框架。

  • 介面:表示集合的抽象資料型別。介面允許獨立於集合具體表示(實現)來操作集合。
  • 實現:對集合介面的具體實現。
  • 演算法:集合上的各種計算操作,演算法應該具有多型性,即同樣的方法可以在不同的實現下的集合介面下使用。

2.Collection

Collection 是集合框架最基本的介面,除了 Map 外,List、Queue、Set 類集合都實現了它。

基本方法

1.基礎操作:

  • int size();
  • boolean isEmpty();
  • boolean contains(Object o);
  • boolean add(E e);
  • boolean remove(Object o);
  • Iterator<E> iterator();

2.bulk 操作有:

  • boolean containsAll(Collection<?> c);
  • boolean addAll(Collection<? extends E> c);
  • boolean removeAll(Collection<?> c);
  • boolean retainAll(Collection<?> c);
  • void clear();

3.stream 流:

  • default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    
  • default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
    

4.針對Array,還有以下的額外操作:

  • Object[] toArray();
  • <T> T[] toArray(T[] a);

容器遍歷

遍歷容器主要有三種方法: 聚合操作、for-each、迭代器Iterator。

String joined = elements.stream() 
    .map(Object::toString) 
    .collect(Collectors.joining(", "));
for (Object o : collection) 
    System.out.println(o);
public interface Iterator<E> { 
    boolean hasNext(); 
    E next(); 
    void remove(); //optional 
} 

對於 Iterator 中的 remove 方法,只能在每次 next 方法之後至多呼叫一次,否則將會丟擲異常。使用迭代器的好處是可以對 collection 中的元素進行刪除。在迭代過程中,Iterator 的 remove 方法是唯一可以刪除元素的操作,如果在迭代過程中通過其他方式對元素有其他修改,將會丟擲異常。

在下面的兩種情況下使用 Iterator,而不是 for-each:

  • 在迭代中需要刪除元素。
  • 並行的對容器進行迭代操作。
static void filter(Collection<?> c) { 
  for (Iterator<?> it = c.iterator(); it.hasNext(); ) 
    if (!cond(it.next())) 
      it.remove(); 
} 

容器實現

集合的實現實現了集合介面的方法,主要包含:

  • General-purpose,使用最廣泛,在日常場景中使用。
  • Special-purpose,對於特殊場景設計,具有非標準的效能特點和使用限制,行為。
  • Concurrent,支援併發。
  • Wrapper,用於組合不同的實現,比如為 general-purpose 實現的集合新增特殊的功能。
  • Convenience,最小實現,通過靜態工廠方法方法獲得,用於替代 general-purpose 的方便,有效的實現。
  • Abstract,骨架實現,方便構成。

上面的實現都允許插入 null 元素;並且都不是執行緒安全的。具有快速失敗(fast-fail)的迭代器設計:當迭代容器時檢測到了並行修改時,迭代器將會立即丟擲異常,防止任意的、不可期的行為發生。它們都實現了 Serializable 介面,並且都實現了 public 的 clone 方法。遺留的 Vector 和 Hashtable 是執行緒安全的,但已經建議不再使用了。如果需要執行緒安全的容器,可以使用 Collections 中的 synchronized wrapper 將上面的實現轉化成執行緒安全的,另外在 Java 的 concurrent 包中,提供了更多高效能的併發容器,比如 BlockingQueue , ConcurrentHashMap 等。

元素排序

集合中某些實現類底層是按照一定規則進行儲存,如 TreeMap 、 TreeSet。這裡有兩種排序方式:自然排序與定製排序。

1.自然排序

Java 提供 Comparable 介面,其中有 compareTo 方法。使用自然排序,需要容器中的元素實現 Comparable 介面中的 compareTo 方法,集合的排序根據 compareTo 方法來比較大小進行排序。

Java 基本型別的包裝類都已實現 compareTo 方法。

對於 Comparable 介面的實現,最好符合以下事項:

  • 符合e1.compareTo(e2) == 0e1.equals(e2)等價。
  • 對 null 元素比較需要丟擲 NullPointerException。因為 null 不是任何類的例項。
  • compareTo 返回負數、零、正數,分別表示小於、等於、大於,且滿足sign(x.compareTo(y)) == -sign(y.compareTo(x))
  • compareTo 的實現滿足傳遞性:x.compareTo(y) == 0 => sign(x.compareTo(z)) = sign(y.compareTo(z))

2.定製排序

如果需要按特殊規則排序或者元素本身不具備比較性時,需要使用定製排序。

定製排序需要一個實現 Comparator 介面的 compare 方法的實現類,並在建立介面時將其作為引數傳遞過去。示例如下:

public class MyComparator implements Comparator {
    @Override
    public int compare(Object o1, Object o2) {
        // 指定排序規則
        return 0;
    }
}
TreeSet tree = new TreeSet(new MyComparator());

3.Collections

collections 是作為 collection 的工具實現類。常用方法示例如下:

包裝器實現(Wrapper Implementations)

collections 的包裝器是裝飾器模式來實現的,包裝器並不提供公用類,都只提供靜態的工廠方法。

1.同步包裝器(Synchronization Wrappers)

同步包裝器為非執行緒安全的 collection 提供同步,通過以下方法,返回對應實現類的同步版本類:

上面的每一個方法返回執行緒安全的基於指定 collection 的同步 collection。

下面以 synchronizedList 方法裝飾 ArrayList 為例,使用以下方式返回執行緒安全的 SynchronizedRandomAccessList:

List<Type> list = Collections.synchronizedList(new ArrayList<Type>()); 

ArrayList 實現了 RandomAccess 介面,應當返回 SynchronizedRandomAccessList ,而 SynchronizedRandomAccessList 繼承 SynchronizedList ,實際上的同步實現在 SynchronizedList 中。(如果裝飾 LinkedList,因為未實現 RandomAccess 介面,直接返回 SynchronizedList。)

SynchronizedList 類中,所有方法內部添加了 synchronized 來同步程式碼塊。

注意:SynchronizedList 只實現了與 ArrayList 實現的介面,對於 ArrayList 提供的額外方法,如 ensureCapacity,無法呼叫。其它同步包裝器也如此。

2.不可變包裝器(Unmodified Wrappers)

不可變包裝器將 collection 進行改變的方法實現為丟擲 UnsupportedOperationException,來保證 collection 不可變或只讀,通過以下方法,返回對應實現類的不可變版本類:

Unmodified Wrappers 的實現方式與 Synchronization Wrappers 實現類似,都採用了裝飾器模式。以返回的 UnmodifiableList 為例,對於原本修改的方法,“重寫”為丟擲異常:

Empty 物件

Collections 以下方法返回空的容器:

它主要用於取代 null 的情況,當某個方法需要一個容器作為引數且不能為 null,你不想提供任何值的時候,就建立一個空的 collection:

tourist.declarePurchases(Collections.emptySet()); 

其實現方式是返回對應的 Empty 物件,以 emptyList 為例:

可以看出,每次呼叫 emptyList 時,返回的都是同一個 EmptyList 物件,以達到共用的目的

不可變單例 Set(Immutable Singleton Set)

singleton 用於建立只包含單個指定元素的 Set。常用的就是移除集合中某個元素:

c.removeAll(Collections.singleton(e));

另外一個類似的就是移除 Map 中指定的 value:

job.values().removeAll(Collections.singleton(LAWYER)); 

不可變多副本列表(Immutable Multiple-Copy List)

nCopies 方法可以建立同個物件的多個副本的不可變 List 。比如建立具有 1000 個 Type 型別的 null 物件:

List<Type> list = new ArrayList<Type>(Collections.nCopies(1000, (Type) null);

第二個主要的用法是在List後面追加:

lovablePets.addAll(Collections.nCopies(69, "fruit bat")); 

元素排序

sort 方法實現了對 List 進行排序,其實歸根到底還是呼叫了 Arrays 的排序演算法。

Arrays 的 mergeSort 用到了快速排序演算法,其比較大小的依據為 Comparable 介面中的 compareTo 方法。

所以呼叫 sort 方法時,需要保證集合中的元素實現了 Comparable 介面

4.Stream API

Stream 是 Java 8 中處理集合的關鍵抽象概念,它可以指定對集合進行的操作,可以執行非常複雜的查詢、過濾和對映資料等操作。

它具有如下特點:

  • Stream 自己不會儲存元素。
  • Stream 不會改變源物件,相反,它們會返回一個持有結果的新 Stream。
  • Stream 操作是延遲執行的,這意味這它們會等到需要結果的時候才執行。