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);
    }

画下流程图:
java8之Collector
上面显示了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);
    }
}

建议大家也动手写一写,对理解会很有帮助。