java SE 1.8中Collection介面分析

chenshijue發表於2016-11-08

Collection介面作為List, Set, Queue等的父類,在平時還是非常常用的。Java8在之前Collection介面的基礎上,使用default關鍵字增加了一些非抽象方法。現在就著重來研究下。

首先看Collection介面的宣告

public interface Collection<E> extends Iterable<E>

首先,Collection是一個模板介面,意味著能夠接受各種物件作為元素型別。它繼承了Iterable,因此,可以使用迭代器來遍歷集合的元素。

下面具體看看宣告的方法。

1. int size() 方法

/**
     * Returns the number of elements in this collection.  If this collection
     * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
     * <tt>Integer.MAX_VALUE</tt>.
     *
     * @return the number of elements in this collection
     */
    int size();

size() 方法返回Collection集合中元素的個數,返回值是int型別的,此方法的註釋中寫道,如果元素個數大於int能表示的最大數量,則只能返回int所能表示的最大數。

2. boolean isEmpty() 方法

這個很簡答,就不說了

3. boolean contain(Object o) 方法

如果Collection中包含至少一個o物件,則返回true。

4. Iterator<E> iterator() 方法

/**
     * Returns an iterator over the elements in this collection.  There are no
     * guarantees concerning the order in which the elements are returned
     * (unless this collection is an instance of some class that provides a
     * guarantee).
     *
     * @return an <tt>Iterator</tt> over the elements in this collection
     */
    Iterator<E> iterator();

返回此Collection的迭代器。迭代器並不能保證返回元素的順序,除非繼承Collection的實現類做了具體的實現來保證迭代器輸出的順序。

5. Object[] toArray() 方法

/**
     * Returns an array containing all of the elements in this collection.
     * If this collection makes any guarantees as to what order its elements
     * are returned by its iterator, this method must return the elements in
     * the same order.
     *
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this collection.  (In other words, this method must
     * allocate a new array even if this collection is backed by an array).
     * The caller is thus free to modify the returned array.
     *
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this collection
     */
    Object[] toArray();
此方法將Collection元素返回成陣列。值得注意的是,返回陣列是重新分配空間儲存的,實際就是所有元素的副本。呼叫者獲取資料之後可以隨意更改而不影響原集合。

6. <T> T[] toArray(T[] a) 方法

/**
     * Returns an array containing all of the elements in this collection;
     * the runtime type of the returned array is that of the specified array.
     * If the collection fits in the specified array, it is returned therein.
     * Otherwise, a new array is allocated with the runtime type of the
     * specified array and the size of this collection.
     *
     * <p>If this collection fits in the specified array with room to spare
     * (i.e., the array has more elements than this collection), the element
     * in the array immediately following the end of the collection is set to
     * <tt>null</tt>.  (This is useful in determining the length of this
     * collection <i>only</i> if the caller knows that this collection does
     * not contain any <tt>null</tt> elements.)
     *
     * <p>If this collection makes any guarantees as to what order its elements
     * are returned by its iterator, this method must return the elements in
     * the same order.
     *
     * <p>Like the {@link #toArray()} method, this method acts as bridge between
     * array-based and collection-based APIs.  Further, this method allows
     * precise control over the runtime type of the output array, and may,
     * under certain circumstances, be used to save allocation costs.
     *
     * <p>Suppose <tt>x</tt> is a collection known to contain only strings.
     * The following code can be used to dump the collection into a newly
     * allocated array of <tt>String</tt>:
     *
     * <pre>
     *     String[] y = x.toArray(new String[0]);</pre>
     *
     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
     * <tt>toArray()</tt>.
     *
     * @param <T> the runtime type of the array to contain the collection
     * @param a the array into which the elements of this collection are to be
     *        stored, if it is big enough; otherwise, a new array of the same
     *        runtime type is allocated for this purpose.
     * @return an array containing all of the elements in this collection
     * @throws ArrayStoreException if the runtime type of the specified array
     *         is not a supertype of the runtime type of every element in
     *         this collection
     * @throws NullPointerException if the specified array is null
     */
    <T> T[] toArray(T[] a);
這個方法和前一個方法方法名相同,但是區別很大。首先,此方法是一個模板方法,可以動態指定型別,前一個方法只返回Object型別的陣列;其次,前一個方法是新分配一段空間來儲存複製物件,而此方法接受一個陣列引數。

此函式接受一個陣列引數,會嘗試將元素放入指定的陣列,如果型別可以成功轉換,並且陣列引數T[] a的空間足以放下所有元素,則將元素放入a中,如果a還有剩餘空間,則填充為null。如果a空間不夠,則會新建一個陣列,並將元素轉換為指定型別加入到陣列中並返回。

例如

public void run() {
		List<Order> orderList1 = new ArrayList<Order>();
		orderList1.add(new Order("0001", "man", 100));              //Order(orderId, createdby, amount)
		orderList1.add(new Order("0002", "man", 1000));
		orderList1.add(new Order("0003", "man", 10000));
		
		Order[] orderContainer1 = new Order[4];
		Order[] orderContainer2 = orderList1.toArray(orderContainer1);
		
		System.out.println(orderContainer1 == orderContainer2);  	//true
		System.out.println(orderContainer1.length);			//4
		
		Order[] orderContainer3 = new Order[1];
		Order[] orderContainer4 = orderList1.toArray(orderContainer3);
		
		System.out.println(orderContainer1 == orderContainer3);  	//false
		System.out.println(orderContainer3.length);			//1
		System.out.println(orderContainer4.length);			//4
		
	}

6. boolean add(E e) 方法

向Collection中新增一個元素。新增方式和具體實現相關,例如List可以新增重複元素,而向Set中新增重複元素返回就是false。

7. boolean remove(Object o) 方法

從Collection中移除一個元素。

8. boolean containsAll(Collection<?> c) 方法

如果Collection中包含所有c中的元素,則返回true。

9. boolean addAll(Collection<?> c) 方法

向Collection中新增所有c中的元素。

10. boolean removeAll(Collection<?> c) 方法

從Collection中刪除所有c中的元素。

11. default boolean removeIf(Predicate<? super E> filter) 方法

/**
     * Removes all of the elements of this collection that satisfy the given
     * predicate.  Errors or runtime exceptions thrown during iteration or by
     * the predicate are relayed to the caller.
     *
     * @implSpec
     * The default implementation traverses all elements of the collection using
     * its {@link #iterator}.  Each matching element is removed using
     * {@link Iterator#remove()}.  If the collection's iterator does not
     * support removal then an {@code UnsupportedOperationException} will be
     * thrown on the first matching element.
     *
     * @param filter a predicate which returns {@code true} for elements to be
     *        removed
     * @return {@code true} if any elements were removed
     * @throws NullPointerException if the specified filter is null
     * @throws UnsupportedOperationException if elements cannot be removed
     *         from this collection.  Implementations may throw this exception if a
     *         matching element cannot be removed or if, in general, removal is not
     *         supported.
     * @since 1.8
     */
    default boolean removeIf(Predicate<? super E> filter)
此方法是java 1.8版本之後新增的。default關鍵字允許在介面類中存在非抽象方法。引數接受一個Predicate型別的函式,通常是lambda表示式。

此函式作用是遍歷整個Collection,刪除符合Predicate filter的條目。

例如,

public void run() {
		List<Order> orderList1 = new ArrayList<Order>();
		orderList1.add(new Order("0001", "man", 100));         //Order(orderId, createdby, amount)
		orderList1.add(new Order("0002", "man", 1000));
		orderList1.add(new Order("0003", "man", 10000));
		
		orderList1.removeIf((o)-> o.getAmount()> 100);
		System.out.println(orderList1.size());  					//1
		
	}
上例中接受了lambda表示式(o)-> o.getAmount()> 100,此表示式判斷order amount是否大於100,如果大於100就返回true。配合removeIf可以刪除Collection中所有amount大於100的order。

12. boolean retainAll(Collection<?> c) 方法

只保留引數c中存在的元素,其他Collection中的引數都刪除。

13. void clear() 方法

清楚Collection中所有元素。

14. boolean equals(Object o) 方法

判斷物件o是否和Collection相等,具體相等的判斷方法有實現類自己決定。

15. int hashCode() 方法

返回Collection的雜湊值。

16. default Spliterator<E> spliterator() 方法

這個又是Java 1.8 中新增的函式,使用default關鍵字提供了預設實現。此方法返回一個Spliterator,Spliterator也是Java 1.8 中引入的新的一種迭代器,除了擁有一般迭代器的遍歷Collection功能,還可以對目標集合進行分割,這種分割特性特別適合多執行緒處理Collection。對於Spliterator可以參考https://blog.logentries.com/2015/10/java-8-introduction-to-parallelism-and-spliterator/,我也會在以後發表分析Spliterator的文章。舉個小例子。

public void run() {
		
		List<Order> orderList1 = new ArrayList<Order>();
		Set<Order> orderSet1 = new HashSet<>();
		
		for (int i = 0; i < 6; i++){
			Order temp = new Order(String.valueOf(i), "man", 100);
			orderList1.add(temp);
			orderSet1.add(temp);
		}
		Spliterator<Order> orderSpliter = orderList1.spliterator();
		Spliterator<Order> orderSpliter1 = orderSpliter.trySplit();
		System.out.println(orderSpliter.getExactSizeIfKnown());			//結果3
		System.out.println(orderSpliter1.getExactSizeIfKnown());		//結果3

	}
以上程式碼使用Spliterator將一個陣列列表分割了一次,得到一個大小為3的新的Spliterator (orderSpliter1),而原來的Spliterator也被分割(orderSpliter),從6變成了3。

17. default Stream<E> stream() 和 default Stream<E> parallelStream() 方法

Java 1.8 的引入的方法,返回流物件,和我們之前的inputstream 和outputstream是不同的概念。借用Stream物件,可以方便的對集合進行聚合、大批量操作等等。它結合lambda表示式,可以簡化程式碼,使用parallelStream充分利用多核計算機的計算能力,提高處理效率。之後我的部落格也會詳細分析Stream的原理和使用。


Collection介面在Java 1.8 中新增了很多新的功能,包括Spliterator、Stream、和結合lambda表示式的操作。感覺Java 1.8 中引入了很多令人興奮的新內容,很值得我們仔細分析和研究。



















相關文章