集合类关系: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
可见,并行运算没法保证每一个元素被处理的顺序。