集合類關係:java
Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap
<!--more-->安全
java.util.Collection 函數
Collection是List和Set的父接口。它繼承了Iterable接口,因此每一個Collection的子類應該是能夠迭代訪問其中的元素的。ui
我注意到一個有意思的函數,該函數在Java1.8中引入。該函數的功能是從集合中刪除全部知足條件的元素,代碼實現平平無奇,主要是函數有一個default修飾。Java8提供了default讓接口中也能夠實現方法體,目的是爲了讓開發者在給interface添加新方法時,沒必要再一一修改實現該接口的類,這些類可使用默認的方法實現。線程
default boolean removeIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); boolean removed = false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; }
Collection的equals方法的重寫須要當心謹慎。簡單的使用引用比較仍是比較簡單安全的,值比較則會變複雜。相等必須是對稱的,約定List只能和其它List相等,Set亦然。因此你本身實現的Collection類在和List、Set比較時應該返回false,由於即便你定製的Collection能夠返回true,可是從List的視角來比較,返回的是false,不知足對稱性。所以,也沒法正確的
實現一個既有List接口,又有Set接口的類。code
遵守約定,若是你重寫了equals方法,那麼你要同時重寫hashCode方法。c1.equals(c2)成立,則c1.hashCode()==c2.hashCode()。繼承
Spliterator接口在Java8中引入,這個單詞是Split和iterator的合成,用來分割集合以給並行處理提供方便。看個例子:遞歸
public class Ripper { public static void main(String[] args) { Collection<Integer> numbers = new ArrayList<>(); for (int i = 0; i < 10; i++) { numbers.add(i); } Spliterator<Integer> sp = numbers.spliterator(); System.out.println(sp.characteristics()); System.out.println(sp.estimateSize()); Spliterator<Integer> sp2=sp.trySplit(); System.out.println(sp.estimateSize()); System.out.println(sp2.estimateSize()); Spliterator<Integer> sp3=sp.trySplit(); System.out.println(sp.estimateSize()); System.out.println(sp3.estimateSize()); sp3. } }
運行結果:接口
16464 10 5 5 3 2
相較於傳統的iterator,spliterator能夠遞歸的對集合進行劃分,每一個spliterator管理了原來集合中的部分元素。可是,每一個spliterator並非線程安全的,因此並行處理時,要保證每個劃分在同一個線程中進行處理。ip
Collection提供Stream對元素進行流處理,其中用到了spliterator。看個例子:
public class Ripper { public static void main(String[] args) { Collection<Integer> numbers = new ArrayList<>(); for (int i = 0; i < 10; i++) { numbers.add(i); } Stream<Integer> stream = numbers.stream(); List<Integer> filterNum=stream.filter(item -> item > 5).collect(Collectors.toList()); for(Integer i:filterNum){ System.out.print(i+" "); } filterNum.set(0,100); System.out.println(); for(Integer i:numbers){ System.out.print(i+" "); } } }
結果:
6 7 8 9 0 1 2 3 4 5 6 7 8 9
集合通過兩步處理,過濾出了全部符合條件的元素。Stream總體處理過程分爲兩步:1.Configuration,2.Processing。Filter是Configuration,collect是Processing。還能夠看出一點,最後獲取的結果List是一個新建的List,並不和原List共享內存中的元素。
再看一個reduce的例子:
public class Ripper { public static void main(String[] args) { Collection<Integer> numbers = new ArrayList<>(); for (int i = 0; i < 10; i++) { numbers.add(i); } Stream<Integer> stream = numbers.stream(); int result=stream.reduce(0, (acc, item) -> acc + item); System.out.println(result); } }
結果是:45。這是一個求和運算,其中第一個參數0
是acc的初始值,acc表示上一步(acc, item) -> acc + item
的結果,item是每次從stream中取的值。這些Configuration並不當即執行,而是等到最後一個Processing函數,統一執行。
在Collection中有parallelStream提供並行運算,而且使用了默認的spliterator對集合進行劃分。例子以下:
public class Ripper { public static void main(String[] args) { Collection<Integer> numbers = new ArrayList<>(); for (int i = 0; i < 10; i++) { numbers.add(i); } Stream<Integer> stream = numbers.parallelStream(); stream.forEach(item -> System.out.print(item+" ")); System.out.println(); stream=numbers.stream(); stream.forEach(item -> System.out.print(item+" ")); } }
結果:
1 2 6 8 0 4 3 5 9 7 0 1 2 3 4 5 6 7 8 9
可見,並行運算沒法保證每一個元素被處理的順序。