概述
Collector接口包含了一系列方法,为实现具体的归约操作(即收集器)提供了范本。我们已经看过了Collector接口中实现的许多收集器(由Collector接口的工具类Collectors提供),例如toList()或groupingBy()。
这也意味着你可以为Collector接口提供自己的实现,从而自由地创建自定义归约操作。
要实现自定义收集器,只需要实现java.util.stream.Collector<T, A, R>
接口即可.
Collector接口的声明如下:
public interface Collector<T, A, R> {
Supplier<A> supplier();
BiConsumer<A, T> accumulator();
BinaryOperator<A> combiner();
Function<A, R> finisher();
Set<Characteristics> characteristics();
}
泛型介绍
-
T:stream在调用collect方法收集前的数据类型
-
A:A是T的累加器,遍历T的时候,会把T按照一定的方式添加到A中,换句话说就是把一些T通过一种方式变成A
-
R:R可以看成是A的累加器,是最终的结果,是把A汇聚之后的数据类型,换句话说就是把一些A通过一种方式变成R
接口介绍
-
supplier: 怎么创建一个累加器
-
accumulator:怎么把一个对象添加到累加器中
-
combiner: 怎么把一个累加器和另一个累加器合并起来,此方法并行时才会调用
-
finisher: 怎么把A转化为R
-
characteristics: 特征值,告诉collect方法在执行归约操作的时候可以应用哪些优化
Characteristics
包含三个项目的枚举:
-
UNORDERED:归约结果不受流中项目的遍历和累积顺序的影响
-
CONCURRENT:accumulator函数可以从多个线程同时调用,且该收集器可以并行归约流。如果收集器没有标为UNORDERED, 那它仅在用于无序数据源时才可以并行归约。
-
IDENTITY_FINISH:这表明完成器方法返回的函数是一个恒等函数,可以跳过。这种情况下,累加器对象将会直接用做归约过程的最终结果。这也意味着,将累加器A不加检查地转换为结果R是安全的。
当Collector设置为IDENTITY_FINISH,finisher方法不会调用,因为不用再类型转换了,中间数据类型就是最终的数据类型。
Stream#collect()源码分析
下面的Stream的实现类ReferencePipeline的collect方法的源码
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) { // @1
A container;
if (isParallel()
&& (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
&& (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) { // @2
container = collector.supplier().get(); // @3
BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
forEach(u -> accumulator.accept(container, u));
}
else {
container = evaluate(ReduceOps.makeRef(collector)); // @4
}
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container
: collector.finisher().apply(container); // @5
}
-
代码@1:函数声明,该方法返回的结果类型为R,传入的行为参数接口为Collector。
-
代码@2:判断是否符合并行化累积与规约的条件。
-
是否是并行流,Stream.stream()方法的流是非并行化流,如果要支持并行化执行,需要使用Stream.parallelStream()方法。
-
Collector(收集器,行为化参数)中收集器行为集合中是否包含Characteristics.CONCURRENT(并行执行),如果不包含该行为,则不支持并行执行。
-
原始流是否有顺序或者收集器的行为集合中明确包含Characteristics.UNORDERED(不要求顺序性)。
-
上述三个条件必须同时满足,才能并行执行,否则串行执行。
-
-
代码@3:并行执行收集动作。
-
代码@4:串行执行收集动作。
-
代码@5:如果收集器收集行为集合中包含Characteristics.IDENTITY_FINISH,则直接返回原始值,否则使用Collector.finishier()方式对计算的值进行函数式计算。
自定义toList
package com.morris.java8.collector;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class ToListCollector<T> implements Collector<T, List<T>, List<T>> {
@Override
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
@Override
public BinaryOperator<List<T>> combiner() {
return (left, right) -> {
left.addAll(right);
return left;
};
}
@Override
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
}
public static void main(String[] args) {
List<Dish> dishList = Dish.createList().stream().filter(Dish::isVegetarian).collect(new ToListCollector<>());
System.out.println(dishList);
}
}
自定义joining
package com.morris.java8.collector;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class JoiningCollector implements Collector<String, StringBuilder, String> {
private String seperator = ",";
public JoiningCollector() {
}
public JoiningCollector(String seperator) {
this.seperator = seperator;
}
@Override
public Supplier<StringBuilder> supplier() {
return StringBuilder::new;
}
@Override
public BiConsumer<StringBuilder, String> accumulator() {
return (sb, str) -> sb.append(str).append(seperator);
}
@Override
public BinaryOperator<StringBuilder> combiner() {
return StringBuilder::append;
}
@Override
public Function<StringBuilder, String> finisher() {
return c -> {
String ret = c.toString();
if (ret.endsWith(seperator)) {
return ret.substring(0, ret.length() - 1);
}
return ret;
};
}
@Override
public Set<Characteristics> characteristics() {
return new HashSet<>();
}
public static void main(String[] args) {
String collect = Arrays.asList("hello", "world", "java", "stream").stream().collect(new JoiningCollector("|"));
System.out.println(collect);
}
}
最后
以上就是靓丽铅笔为你收集整理的【java8】自定义Collector泛型介绍接口介绍CharacteristicsStream#collect()源码分析自定义toList自定义joining的全部内容,希望文章能够帮你解决【java8】自定义Collector泛型介绍接口介绍CharacteristicsStream#collect()源码分析自定义toList自定义joining所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复