java8源码_Java8-11-Stream收集器源码分析与⾃定义收集器上⼀篇我们系统的学习了Stream的分组分区,本篇我们学习下Stream中的收集器。
那么什么是收集器呢,在之前的课程中,我们学习了可以通过Stream对集合中的元素进⾏例如映射,过滤,分组,分区等操作。例如下⾯将所有元素转成⼤写就是⽤map映射操作
List list = Arrays.asList("hello", "world", "helloworld");
List collect = list.stream().map(String::toUpperCase).List());
现在再看上⾯的程序就很容易理解了,但是我们之前的⽂章只是对于中间操作(map⽅法等)进⾏了详细的介绍,包括lambda表达式和⽅法引⽤以及各种函数式接⼝。接下来我们将注意⼒放在collect⽅法上,collect接收⼀个Collector类型的参数,Collector就是Java8中的收集器。
R collect(Collector super T, A, R> collector);
也就是说collect⽅法最终需要接收⼀个收集器作为结果容器。虽然⼤多数收集器不需要我们⾃⾏创建,可以借助Collectors类提供的创建常⽤收集器的⽅法,例如toList() toSet() toCollection(Supplier collectionFactory)等⽅法。但是深⼊理解收集器的实现,对我们编写正确的程序会起到极⼤的作⽤。
下⾯就是toList⽅法的具体实现
public static Collector> toList() {
return new CollectorImpl<>((Supplier>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
通过查看toList⽅法源码,知道返回的收集器是⼀个CollectorImpl的实例。⽽CollectorImpl就是收集器Collector的⼀个实现类,被定义在Collectors辅助类中,⽤于创建常⽤的收集器实例供我们使⽤
/**
java stream* Simple implementation class for {@code Collector}.
*
* @param the type of elements to be collected
* @param the type of the result
*/
static class CollectorImpl implements Collector {
private final Supplier supplier;
private final BiConsumer accumulator;
private final BinaryOperator combiner;
private final Function finisher;
private final Set characteristics;
CollectorImpl(Supplier supplier,
BiConsumer accumulator,
BinaryOperator combiner,
Function finisher,
Set characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
thisbiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier supplier,
BiConsumer accumulator,
BinaryOperator combiner,
Set characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics); }
@Override
public BiConsumer accumulator() {
return accumulator;
}
@Override
public Supplier supplier() {
return supplier;
}
@Override
public BinaryOperator combiner() {
return combiner;
}
@Override
public Function finisher() {
return finisher;
}
@Override
public Set characteristics() {
return characteristics;
}
}
CollectorImpl构造⽅法根据传⼊的不同参数实现Collector接⼝中的⽅法,例如上⾯的toList
所以如果要实现⾃定义的收集器,就需要我们⾃⼰来实现Collector接⼝中的各个⽅法,接下来就接⼝中的每个⽅法进⾏分析
/*
* @param the type of input elements to the reduction operation
* @param the mutable accumulation type of the reduction operation (often
* hidden as an implementation detail)
* @param the result type of the reduction operation
* @since 1.8
*/
public interface Collector {
在分析Collector接⼝之前,我们需要关注下Collector接⼝的三个泛型
泛型T 表⽰向集合中放⼊的元素类型
泛型A 表⽰可变的中间结果容器类型
泛型R 表⽰最终的结果容器类型
下⾯我们还会提到这些泛型,接下来看下Collector接⼝中的⽅法
/**
* A function that creates and returns a new mutable result container.
*
* @return a function which returns a new, mutable result container
*/
Supplier supplier();
supplier()是⼀个创建并返回⼀个新的可变的结果容器的函数,也就是收集器⼯作时,⾸先要将收集的元素(也就是泛型T类型)放到supplier()创建的容器中。
/**
* A function that folds a value into a mutable result container.
*
* @return a function which folds a value into a mutable result container
*/
BiConsumer accumulator();
accumulator()是将⼀个个元素(泛型T类型)内容放到⼀个可变的结果容器(泛型A类型)中的函数,这个结果容器就是上⾯supplier()函数所创建的。
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*
* @return a function which combines two partial results into a combined
* result
*/
BinaryOperator combiner();
combiner()会接收两部分结果容器(泛型A类型)并且将他们进⾏合并。即可以将⼀个结果集合并到另⼀个结果集中,也可以将这两个结果集合并到⼀个新的结果集中,并将得到的并集返回。
这⾥所说的结果集是指supplier()创建的结果容器中的所有元素,但是为什么说会接收两个结果集呢,这⾥涉及到并⾏流机制,如果是串⾏流执⾏只会⽣成⼀个结果容器不需要combiner()
函数进⾏合并,但是如果是并⾏流会⽣成多个结果容器,需要combiner()分别进⾏两两合并,最终得到⼀个最终的结果容器(泛型R类型)
其实并⾏流这⾥说的并不严谨,并⾏流需要结合Characteristics中的CONCURRENT特性值才能判断
是否会产⽣多个中间可变结果容器,我们在后续分析收集器执⾏机制时,会结合⽰例来说明这部分的区别。
/**
* Perform the final transformation from the intermediate accumulation type
* {@code A} to the final result type {@code R}.
*
*
If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result
*/
Function finisher();
finisher()会执⾏最终的转换操作,也就是说如果我们需要将得到的结果再次进⾏类型转换或者其他⼀些逻辑处理的话,可以通过finisher()完成。如果收集器包含了
Characteristics.IDENTITY_FINISH特性,说明不需要进⾏任何转换操作了,那么finisher()函数就不会执⾏。
/**
* Returns a {@code Set} of {@code Collector.Characteristics} indicating
* the characteristics of this Collector. This set should be immutable.
*
* @return an immutable set of collector characteristics
*/
Set characteristics();
最后来看下characteristics()函数,上⾯我们不⽌⼀次提到了收集器的特性值这个概念,characteristics()⽅法就是返回这些特性值的函数。这些特性值是我们创建收集器时,⾃⼰通过Characteristics指定的。Characteristics是⼀个定义在Collector接⼝中的枚举,它包括三个枚举值CONCURRENT,UNORDERED,IDENTITY_FINISH
/**
* Characteristics indicating properties of a {@code Collector}, which can
* be used to optimize reduction implementations.
*/
enum Characteristics {
/**
* Indicates that this collector is concurrent, meaning that
* the result container can support the accumulator function being
* called concurrently with the same result container from multiple
* threads.
*
*
If a {@code CONCURRENT} collector is not also {@code UNORDERED},
* then it should only be evaluated concurrently if applied to an
* unordered data source.
*/
CONCURRENT,
/
**
* Indicates that the collection operation does not commit to preserving
* the encounter order of input elements. (This might be true if the
* result container has no intrinsic order, such as a {@link Set}.)
*/
UNORDERED,
/**
* Indicates that the finisher function is the identity function and
* can be elided. If set, it must be the case that an unchecked cast
* from A to R will succeed.
*/
IDENTITY_FINISH
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论