java8之Collector
Collector组成
Supplier<A> supplier(): 创建一个容器
BiConsumer<A, T> accumulator(): 将元素添加到容器中
BinaryOperator<A> combiner(): 将两个容器合并为一个结果容器
Function<A, R> finisher(): 对结果容器作相应的变换
Set<Collector.Characteristics>:对上述过程做优化和控制
以toList()方法为例讲解下它的实现
Collectors.toList()的源码
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
画下流程图:
上面显示了Collectors.toList()的整个流程:
1.创建一个空器 :ArrayList::new
2.将流中的元素添加到容器中: List::add
3.将两个容器合并:left.addAll(right)
4.将结果较换成想要的格式:此例子中该方法不执行(下面会讲为什么不执行)
自定义一个Collector方法来理解下它的实现
下面将写一个方法来计算List集合中的值的总和
1.首先创建一个容器:BigDecimalSum
package com.cn.stream;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalSum {
BigDecimal sum;
public BigDecimalSum(BigDecimal sum) {
this.sum = sum.setScale(2,RoundingMode.HALF_UP);
System.out.println("创建一个容器");
}
public BigDecimal accumulator(BigDecimal item) {
this.sum = this.sum.add(item.setScale(2, RoundingMode.HALF_UP));
System.out.println("accumulator="+sum);
return sum;
}
public BigDecimalSum combiner(BigDecimalSum it) {
this.sum=this.sum.add(it.sum);
System.out.println("combiner="+this+",this.sum="+this.sum+"it.sum="+it.sum);
return this;
}
public String finisher() {
System.out.println("finisher="+this.sum.toString());
return this.sum.toString();
}
}
然后:实现Collector接口
package com.cn.stream;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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;
import java.util.stream.Stream;
/**
* 自定义Collector
*/
public class CustomCollector {
@Test
public void collector_test(){
List<BigDecimal> bigDecimals = new ArrayList<BigDecimal>();
bigDecimals.add(new BigDecimal(3.4544) );
bigDecimals.add(new BigDecimal(2.6744) );
bigDecimals.add(new BigDecimal(9.0444) );
Stream<BigDecimal> bigDecimalStream = bigDecimals.parallelStream();
String bigDecimalSum = bigDecimalStream.collect(new Collector<BigDecimal, BigDecimalSum, String>() {
@Override
//创建容器
public Supplier<BigDecimalSum> supplier() {
return () -> new BigDecimalSum(BigDecimal.ZERO);
}
@Override
//将流中的值添加到容器中
public BiConsumer<BigDecimalSum, BigDecimal> accumulator() {
return BigDecimalSum::accumulator;
}
@Override
//将多线程创建的容器合并
public BinaryOperator<BigDecimalSum> combiner() {
return BigDecimalSum::combiner;
}
@Override
//将结果较换成想要的格式
public Function<BigDecimalSum, String> finisher() {
return BigDecimalSum::finisher;
}
@Override
//Characteristics:一种契约或者说规定
public Set<Characteristics> characteristics() {
Set<Characteristics> characteristicsList = new HashSet<Characteristics>();
//characteristicsList.add(Characteristics.IDENTITY_FINISH);
//IDENTITY_FINISH :finisher 函数不会执行。一旦有这个值,程序就会认为可变的结果容器结果就是最终结果,没有必要再去转换,
//也就是new Collector后面BigDecimalSum要和String一致
//CONCURRENT:c accumulator 函数可以从多个线程同时调用,且该收集器可以并行归约流。如果收集器没有标为 UNORDERED ,
// 那它仅在用于无序数据源时才可以并行归约
//UNORDERED:归约结果不受流中项目的遍历和累积顺序的影响
return characteristicsList;
}
});
System.out.println("---bigDecimalSum----"+bigDecimalSum);
}
}
建议大家也动手写一写,对理解会很有帮助。