前言
集合框架是一个用来代表和操纵集合的统一架构。Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。
1.顶级接口(root interface)
collection和map都是JDK1.2推出来的。但要注意一点在jdk1.5后collection并不是最高的接口,它之上还有个接口 Iterable,这个接口严格上来讲跟集合并没有关系,这只是java对单元素集合操作的增强(允许单元素集合使用for-each loop)语句。
java中比较重要的集合关系如下,其中标红的表示为JDK1.5之后的,其它在jdk1.2时就已经定义了。 到目前JDK1.8,集合框架都未有大的变动(并不是所有语言都这样,像python就有版本2到3之间非常大的变化和不兼容,导致很多基于python2的程序升级到python3都很费劲),这一方面说明了java语言设计人员的扎实基础,另一方面也说明了java集合框架发展到目前这一阶段,已经比较成熟了,这是任何开发人员都比较在意的地方。
2.Collection
集合接口中定义的所有方法,颜色深一些的方法都是比较常用的。
int size(); | Returns the number of elements in this collection. |
boolean isEmpty(); | Returns <tt>true</tt> if this collection contains no elements. |
boolean contains(Object o); | Returns <tt>true</tt> if this collection contains the specified element. |
Iterator<E> iterator(); | Returns an iterator over the elements in this collection. |
Object[] toArray(); | Returns an array containing all of the elements in this collection. |
<T> T[] toArray(T[] a); | Returns an array containing all of the elements in this collection; |
boolean add(E e); | Ensures that this collection contains the specified element. |
boolean remove(Object o); | Removes a single instance of the specified element from this |
boolean containsAll(Collection<?> c); | Returns <tt>true</tt> if this collection contains all of the elements in the specified collection. |
boolean addAll(Collection<? extends E> c); | Adds all of the elements in the specified collection to this collection(optional operation). |
boolean removeAll(Collection<?> c); | Removes all of this collection's elements that are also contained in thespecified collection (optional operation). |
default boolean removeIf(Predicate<? super E> filter) | Removes all of the elements of this collection that satisfy the given predicate. |
boolean retainAll(Collection<?> c); | Retains only the elements in this collection that are contained in the specified collection (optional operation). |
void clear(); | Removes all of the elements from this collection (optional operation). |
boolean equals(Object o); | Compares the specified object with this collection for equality. |
int hashCode(); | Returns the hash code value for this collection. |
default <E> spliterator() | Creates a {@link Spliterator} over the elements in this collection. |
default Stream<E> stream() | Returns a sequential {@code Stream} with this collection as its source. |
default Stream<E> parallelStream() | Returns a possibly parallel {@code Stream} with this collection as its source. |
3.Collection接口方法详解
这里的详解,只说明接口定义方法的要求,具体功能实现得看实现类。很容易看明白的方法就不说明了。
3.1 Iterator<E> iterator();
Returns an iterator over the elements in this collection.这个要求集合返回一个迭代器iterator,迭代器就是一个可以遍历所有集合元素的工具。它要求必须具有以下所有功能方法。
boolean hasNext(); | Returns {@code true} if the iteration has more elements. |
E next(); | Returns the next element in the iteration. |
default void remove() | Removes from the underlying collection the last element returned by this iterator (optional operation). |
default void forEachRemaining(Consumer<? super E> action) | Performs the given action for each remaining element until all elements have been processed or the action throws an exception |
其中hasNext、next、remove方法都是jdk1.2就有的,并且很容易就看明白;forEachRemaining为jdk 1.8新增的,作用为遍历集合中的所有保持元素(同一个迭代器如果有多个地方调用,遍历元素的指向会累计),并执行Consumer的accept方法(需要使用者实现Consumer接口,在Consumer的accept方法中对元素进行自定义处理)。
例子:打印集合(1,2)中的元素,每个元素都乘以10。
迭代器指向累计,上面会输出10 20,下面这个则只会输出20。
3.2 default boolean removeIf(Predicate<? super E> filter)
根据指定方法移除集合中的元素,如移除集合(1,2)中大于1的元素。
3.3 boolean retainAll(Collection<?> c);
保留当前集合和另一个集合的交集数据。
上面会输出true和[1]。
3.4 default <E> spliterator()
JDK1.8新增方法,获取一个集合分离器spliterator,分离器的设计的目的:
1.support efficient parallel traversal in addition to sequential traversal(支持高效的并行遍历)
2.impose smaller per-element overhead than Iterator(施加比迭代器更小的每元素开销)
3.avoid the inherent race involved in having separate methods for hasNext() and next() (避免为 Iterator.hasNext()和Iterator.next()使用单独的方法所涉及的固有竞争)。
spliterator并行遍历需要使用到trySplit方法(每次都会分离当前集合的一半元素到另一个分离器,注意剩下的元素还在当前分离器中,也需要进行处理)。
spliterator并行遍历例子如下(至于分割成多少个集合片段和使用多少并行线程处理,需要自己写代码控制):
public class Test {
public static void main(String[] args) throws Exception{
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);
// 线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 集合分离器
Spliterator<Integer> spliterator = list.spliterator();
// 分离出来的前一半集合元素执行业务逻辑
Spliterator<Integer> preHalfSpliterator = spliterator.trySplit(); // trySplit获取集合中的前一半
if(preHalfSpliterator != null){
preHalfSpliterator.forEachRemaining(new TaskClass<>(executorService, "任务前半部分"));
}
// 剩下的集合元素执行业务逻辑
spliterator.forEachRemaining(new TaskClass<>(executorService, "任务后半部分"));
}
static class TaskClass<T> implements Consumer<T>{
String taskName;
ExecutorService executorService;
public TaskClass(ExecutorService executorService, String taskName){
this.executorService = executorService;
this.taskName = taskName;
}
@Override
public void accept(T t) {
executorService.execute(() -> {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " " + taskName + "打印了" + t.toString());
});
}
}
}
后面部分为Spliterator和Iterator的比较。
ArrayList中Iterator的hasNext和next代码实现如下:
ArrayList通过Iterator遍历元素并打印的方式如下:
ArrayList中Spliterator如果需要遍历,需要用到tryAdvance方法,源码如下:
ArrayList通过分离器spliterator遍历元素并打印方式如下(tryAdvance方法返回的不是当前元素,而是当前元素是否存在的boolean值,并且会移动数组下标,遍历的元素丢给了Consumer的accept方法进行处理)。