zoukankan      html  css  js  c++  java
  • JDK1.8新特性——Collector接口和Collectors工具类

    JDK1.8新特性——Collector接口和Collectors工具类

    摘要:本文主要学习了在Java1.8中新增的Collector接口和Collectors工具类,以及使用它们在处理集合时的改进和优化。

    部分内容来自以下博客:

    https://www.jianshu.com/p/7eaa0969b424

    流式处理

    JDK1.8中新增的流式处理提供了一种高效且易于使用的处理数据的方式,它可以对集合执行非常复杂的查找、过滤和映射数据等操作,极大的简化了对于集合的使用。借助流式处理,可以像使用SQL语句一样对集合进行操作。

    JDK1.8通过内部迭代来实现对流的处理,一个流式处理可以分为三个部分:转换成流、中间操作、终止操作。

    转换成流

    对于集合,可以使用集合类中的stream()方法或者parallelStream()方法将集合转换成流。

    中间操作

    中间操作可以对流进行处理并返回处理后的流对象,多个中间操作可以连接起来形成一个流水线,直到执行终止操作结束流的执行。

    终止操作

    终止操作会对经过中间操作后得到的流进行处理,返回任何不是流的数据。

    Collector接口

    在对流进行的终止操作中,有一个方法是collect,其作用是收集元素并进行处理,最终返回处理后的非流对象。

    查看其方法定义如下:

    1 <R, A> R collect(Collector<? super T, A, R> collector);

    可以看到,collect方法要求传入一个Collector接口的实例对象,Collector可以看做是用来处理流的工具,在Collectors里面封装了很多Collector工具。

    全局变量

    Collector主要包含五个参数,它的行为也是由这五个参数来定义的,如下所示:

     1 // supplier参数用于生成结果容器,容器类型为A。
     2 Supplier<A> supplier();
     3 // accumulator用于归纳元素,泛型T就是元素,它会将流中的元素同结果容器A发生操作。
     4 BiConsumer<A, T> accumulator();
     5 // combiner用于合并两个并行执行的结果,将其合并为最终结果A。
     6 BinaryOperator<A> combiner();
     7 // finisher用于将之前完整的结果R转为A。
     8 Function<A, R> finisher();
     9 // characteristics表示当前Collector的特征值,是一个不可变的Set。
    10 Set<Characteristics> characteristics();

    枚举

    Characteristics这个特征值是一个枚举:

    1 enum Characteristics {
    2     // 多线程并行。
    3     CONCURRENT,
    4     // 无序。
    5     UNORDERED,
    6     // 无需转换结果。
    7     IDENTITY_FINISH
    8 }

    构造方法

    Collector拥有两个of方法用于生成Collector实例,其中一个拥有上面所有五个参数,另一个四个参数,不包括finisher参数。

     1 // 四参方法,用于生成一个Collector,T代表流中的元素,R代表最终的结果。因为没有finisher参数,所以需要有IDENTITY_FINISH特征值。
     2 public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
     3                                           BiConsumer<R, T> accumulator,
     4                                           BinaryOperator<R> combiner,
     5                                           Characteristics... characteristics) {
     6     Objects.requireNonNull(supplier);
     7     Objects.requireNonNull(accumulator);
     8     Objects.requireNonNull(combiner);
     9     Objects.requireNonNull(characteristics);
    10     Set<Characteristics> cs = (characteristics.length == 0)
    11                               ? Collectors.CH_ID
    12                               : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
    13                                                                        characteristics));
    14     return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
    15 }
    16 
    17 // 五参方法,用于生成一个Collector,T代表流中的元素,A代表中间结果,R代表最终结果,finisher用于将A转换为R。
    18 public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
    19                                              BiConsumer<A, T> accumulator,
    20                                              BinaryOperator<A> combiner,
    21                                              Function<A, R> finisher,
    22                                              Characteristics... characteristics) {
    23     Objects.requireNonNull(supplier);
    24     Objects.requireNonNull(accumulator);
    25     Objects.requireNonNull(combiner);
    26     Objects.requireNonNull(finisher);
    27     Objects.requireNonNull(characteristics);
    28     Set<Characteristics> cs = Collectors.CH_NOID;
    29     if (characteristics.length > 0) {
    30         cs = EnumSet.noneOf(Characteristics.class);
    31         Collections.addAll(cs, characteristics);
    32         cs = Collections.unmodifiableSet(cs);
    33     }
    34     return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
    35 }

    Collectors工具类

    Collectors是一个工具类,是JDK预实现Collector的工具类,它内部提供了多种Collector。

    toCollection方法

    将流中的元素全部放置到一个集合中返回,这里使用Collection,泛指多种集合。

    方法:

    1 public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
    2     return new CollectorImpl<>(
    3             collectionFactory, Collection<T>::add,
    4             (r1, r2) -> { r1.addAll(r2); return r1; }, 
    5             CH_ID);
    6 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     LinkedList<String> newList = list.stream().collect(Collectors.toCollection(LinkedList::new));
    5     System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345]
    6 }

    toList方法

    将流中的元素放置到一个List集合中返回,默认为ArrayList。

    方法:

    1 public static <T>
    2 Collector<T, ?, List<T>> toList() {
    3     return new CollectorImpl<>(
    4             (Supplier<List<T>>) ArrayList::new, List::add,
    5             (left, right) -> { left.addAll(right); return left; },
    6             CH_ID);
    7 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     List<String> newList = list.stream().collect(Collectors.toList());
    5     System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345]
    6 }

    toSet方法

    将流中的元素放置到一个Set集合中返回,默认为HashSet。

    方法:

    1 public static <T> Collector<T, ?, Set<T>> toSet() {
    2     return new CollectorImpl<>(
    3             (Supplier<Set<T>>) HashSet::new, Set::add,
    4             (left, right) -> { left.addAll(right); return left; },
    5             CH_UNORDERED_ID);
    6 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     Set<String> newSet = list.stream().collect(Collectors.toSet());
    5     System.out.println(newSet);// [100, 123, 521, 345, 228, 838, 250]
    6 }

    toMap方法

    根据传入的键生成器和值生成器,将生成的键和值保存到一个Map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的Map。

    还有支持并发toConcurrentMap方法,同样有三种重载方法,与toMap基本一致,只是它最后使用的Map是并发ConcurrentHashMap。

    方法:

     1 // 指定键和值的生成方式,遇到键冲突的情况默认抛出异常,默认使用HashMap。
     2 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
     3             Function<? super T, ? extends K> keyMapper,
     4             Function<? super T, ? extends U> valueMapper) {
     5     return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
     6 }
     7 // 指定键和值的生成方式,遇到键冲突的情况使用传入的方法处理,默认使用HashMap。
     8 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
     9             Function<? super T, ? extends K> keyMapper,
    10             Function<? super T, ? extends U> valueMapper,
    11             BinaryOperator<U> mergeFunction) {
    12     return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
    13 }
    14 // 指定键和值的生成方式,遇到键冲突的情况使用传入的方法处理,使用传入的Map类型返回数据。前两种方式最终还是调用此方法来返回Map数据。
    15 public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
    16             Function<? super T, ? extends K> keyMapper,
    17             Function<? super T, ? extends U> valueMapper,
    18             BinaryOperator<U> mergeFunction,
    19             Supplier<M> mapSupplier) {
    20     BiConsumer<M, T> accumulator = (map, element) -> map.merge(
    21             keyMapper.apply(element), 
    22             valueMapper.apply(element), 
    23             mergeFunction);
    24     return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    25 }

    实例:

     1 public static void main(String[] args) {
     2     Map<String, String> newMap = null;
     3     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     4     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     5     // 123和100的键都是1,导致冲突,默认抛出异常,使用limit截取前两个元素。
     6     newMap = list.stream().limit(2).collect(Collectors.toMap(e -> e.substring(0, 1), e -> e));
     7     System.out.println(newMap);// {1=123, 5=521}
     8     // 传入主键冲突时的处理方法,保留先插入的值,默认使用HashMap,对主键由小到大排序。
     9     newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> m));
    10     System.out.println(newMap);// {1=123, 2=228, 3=345, 5=521, 8=838}
    11     // 传入主键冲突时的处理方法,保留新插入的值,默认使用LinkedHashMap,对主键按照插入顺序排序。
    12     newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> n, LinkedHashMap::new));
    13     System.out.println(newMap);// {1=100, 5=521, 2=250, 8=838, 3=345}
    14 }

    joining方法

    将流中的元素全部以字符串的方式连接到一起,可以指定连接符,也可以指定前后缀。

    方法:

     1 // 将流中的元素全部以字符串的方式连接到一起,不使用连接符,也不指定前后缀。
     2 public static Collector<CharSequence, ?, String> joining() {
     3     return new CollectorImpl<CharSequence, StringBuilder, String>(
     4             StringBuilder::new, StringBuilder::append,
     5             (r1, r2) -> { r1.append(r2); return r1; },
     6             StringBuilder::toString, CH_NOID);
     7 }
     8 // 将流中的元素全部以字符串的方式连接到一起,使用指定的连接符,不指定前后缀。
     9 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
    10     return joining(delimiter, "", "");
    11 }
    12 // 将流中的元素全部以字符串的方式连接到一起,使用指定的连接符,使用指定的前后缀。
    13 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
    14                                                          CharSequence prefix,
    15                                                          CharSequence suffix) {
    16     return new CollectorImpl<>(
    17             () -> new StringJoiner(delimiter, prefix, suffix),
    18             StringJoiner::add, StringJoiner::merge,
    19             StringJoiner::toString, CH_NOID);
    20 }

    实例:

     1 public static void main(String[] args) {
     2     String str = null;
     3     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     4     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     5     str = list.stream().collect(Collectors.joining());
     6     System.out.println(str);// 123521100228838250345
     7     str = list.stream().collect(Collectors.joining("-"));
     8     System.out.println(str);// 123-521-100-228-838-250-345
     9     str = list.stream().collect(Collectors.joining("-", "<", ">"));
    10     System.out.println(str);// <123-521-100-228-838-250-345>
    11 }

    mapping方法

    将流中的元素按照传入的方法进行处理,并将结果按照指定的格式返回。

    方法:

     1 public static <T, U, A, R>
     2 Collector<T, ?, R> mapping(
     3             Function<? super T, ? extends U> mapper,
     4             Collector<? super U, A, R> downstream) {
     5     BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
     6     return new CollectorImpl<>(
     7             downstream.supplier(),
     8             (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
     9             downstream.combiner(),
    10             downstream.finisher(),
    11             downstream.characteristics());
    12 }

    实例:

    1 public static void main(String[] args) {
    2     List<Score> scoreList = new ArrayList<Score>();
    3     scoreList.add(new Score("2019", "10", "张三", 1));
    4     scoreList.add(new Score("2019", "11", "李四", 1));
    5     scoreList.add(new Score("2019", "12", "王五", 1));
    6     List<String> names = scoreList.stream().collect(Collectors.mapping(Score::getName, Collectors.toList()));
    7     System.out.println(names);// [张三, 李四, 王五]
    8 }

    collectingAndThen方法

    该方法是按照传入的collector处理完之后,对归纳的结果进行再处理。

    方法:

     1 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(
     2             Collector<T,A,R> downstream,
     3             Function<R,RR> finisher) {
     4     Set<Collector.Characteristics> characteristics = downstream.characteristics();
     5     if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
     6         if (characteristics.size() == 1)
     7             characteristics = Collectors.CH_NOID;
     8         else {
     9             characteristics = EnumSet.copyOf(characteristics);
    10             characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
    11             characteristics = Collections.unmodifiableSet(characteristics);
    12         }
    13     }
    14     return new CollectorImpl<>(downstream.supplier(),
    15                                downstream.accumulator(),
    16                                downstream.combiner(),
    17                                downstream.finisher().andThen(finisher),
    18                                characteristics);
    19 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     Integer size = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
    5     System.out.println(size);// 7
    6 }

    counting方法

    该方法主要用来计数。

    方法:

    1 public static <T> Collector<T, ?, Long> counting() {
    2     return reducing(0L, e -> 1L, Long::sum);
    3 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     Long count = list.stream().collect(Collectors.counting());
    5     System.out.println(count);// 7
    6 }

    reducing方法

    对流中的元素做统计归纳,有三个重载方法,和Stream里的三个reduce方法对应,二者是可以替换使用的,作用完全一致。

    方法:

     1 // 返回一个可以直接产生Optional类型结果的Collector,没有初始值。
     2 public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {
     3     class OptionalBox implements Consumer<T> {
     4         T value = null;
     5         boolean present = false;
     6 
     7         @Override
     8         public void accept(T t) {
     9             if (present) {
    10                 value = op.apply(value, t);
    11             }
    12             else {
    13                 value = t;
    14                 present = true;
    15             }
    16         }
    17     }
    18     return new CollectorImpl<T, OptionalBox, Optional<T>>(
    19             OptionalBox::new, OptionalBox::accept,
    20             (a, b) -> { if (b.present) a.accept(b.value); return a; },
    21             a -> Optional.ofNullable(a.value), CH_NOID);
    22 }
    23 // 返回一个可以直接产生结果的Collector,指定初始值。
    24 public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {
    25     return new CollectorImpl<>(
    26             boxSupplier(identity),
    27             (a, t) -> { a[0] = op.apply(a[0], t); },
    28             (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
    29             a -> a[0],
    30             CH_NOID);
    31 }
    32 // 返回一个可以直接产生结果的Collector,指定初始值,在返回结果之前先使用传入的方法将流进行转换。
    33 public static <T, U> Collector<T, ?, U> reducing(
    34             U identity,
    35             Function<? super T, ? extends U> mapper,
    36             BinaryOperator<U> op) {
    37     return new CollectorImpl<>(
    38             boxSupplier(identity),
    39             (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
    40             (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
    41             a -> a[0], CH_NOID);
    42 }

    实例:

     1 public static void main(String[] args) {
     2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     4     Optional<Integer> optional = list.stream().limit(4).map(String::length).collect(Collectors.reducing(Integer::sum));
     5     System.out.println(optional);// Optional[12]
     6     Integer integer = list.stream().limit(3).map(String::length).collect(Collectors.reducing(0, Integer::sum));
     7     System.out.println(integer);// 9
     8     Integer sum = list.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum));
     9     System.out.println(sum);// 12
    10 }

    minBy方法和maxBy方法

    生成一个用于获取最小值或者最大值的Optional结果的Collector。

    方法:

    1 public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) {
    2     return reducing(BinaryOperator.minBy(comparator));
    3 }
    4 public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) {
    5     return reducing(BinaryOperator.maxBy(comparator));
    6 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     Optional<String> max = list.stream().collect(Collectors.maxBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n)));
    5     System.out.println(max);// Optional[838]
    6     Optional<String> min = list.stream().collect(Collectors.minBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n)));
    7     System.out.println(min);// Optional[100]
    8 }

    summingInt方法、summingLong方法和summingDouble方法

    生成一个用于求元素和的Collector,首先将元素转换类型,然后再求和。

    参数的作用就是将元素转换为指定的类型,最后结果与转换后类型一致。

    方法:

     1 public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) {
     2     return new CollectorImpl<>(
     3             () -> new int[1],
     4             (a, t) -> { a[0] += mapper.applyAsInt(t); },
     5             (a, b) -> { a[0] += b[0]; return a; },
     6             a -> a[0], CH_NOID);
     7 }
     8 public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) {
     9     return new CollectorImpl<>(
    10             () -> new long[1],
    11             (a, t) -> { a[0] += mapper.applyAsLong(t); },
    12             (a, b) -> { a[0] += b[0]; return a; },
    13             a -> a[0], CH_NOID);
    14 }
    15 public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) {
    16     return new CollectorImpl<>(
    17             () -> new double[3],
    18             (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
    19                         a[2] += mapper.applyAsDouble(t); },
    20             (a, b) -> { sumWithCompensation(a, b[0]);
    21                         a[2] += b[2]; return sumWithCompensation(a, b[1]); },
    22             a -> computeFinalSum(a), CH_NOID);
    23 }

    实例:

     1 public static void main(String[] args) {
     2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     4     Integer intCollect = list.stream().collect(Collectors.summingInt(Integer::parseInt));
     5     System.out.println(intCollect);// 2405
     6     Long longCollect = list.stream().collect(Collectors.summingLong(Long::parseLong));
     7     System.out.println(longCollect);// 2405
     8     Double doubleCollect = list.stream().collect(Collectors.summingDouble(Double::parseDouble));
     9     System.out.println(doubleCollect);// 2405.0
    10 }

    summarizingInt方法、summarizingLong方法和summarizingDouble方法

    这三个方法适用于汇总的,返回值分别是IntSummaryStatistics、LongSummaryStatistics和DoubleSummaryStatistics。

    在这些返回值中包含有流中元素的指定结果的数量、和、最大值、最小值、平均值。

    方法:

     1 public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
     2     return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
     3             IntSummaryStatistics::new,
     4             (r, t) -> r.accept(mapper.applyAsInt(t)),
     5             (l, r) -> { l.combine(r); return l; }, CH_ID);
     6 }
     7 public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
     8     return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
     9             LongSummaryStatistics::new,
    10             (r, t) -> r.accept(mapper.applyAsLong(t)),
    11             (l, r) -> { l.combine(r); return l; }, CH_ID);
    12 }
    13 public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
    14     return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
    15             DoubleSummaryStatistics::new,
    16             (r, t) -> r.accept(mapper.applyAsDouble(t)),
    17             (l, r) -> { l.combine(r); return l; }, CH_ID);
    18 }

    实例:

     1 public static void main(String[] args) {
     2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     4     IntSummaryStatistics intSummaryStatistics = list.stream().collect(Collectors.summarizingInt(Integer::parseInt));
     5     System.out.println(intSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838}
     6     LongSummaryStatistics longSummaryStatistics = list.stream().collect(Collectors.summarizingLong(Long::parseLong));
     7     System.out.println(longSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838}
     8     DoubleSummaryStatistics doubleSummaryStatistics = list.stream().collect(Collectors.summarizingDouble(Double::parseDouble));
     9     System.out.println(doubleSummaryStatistics);// {count=7, sum=2405.000000, min=100.000000, average=343.571429, max=838.000000}
    10 }

    averagingInt方法、averagingLong方法和averagingDouble方法

    生成一个用于求元素平均值的Collector,首先将元素转换类型,然后再求平均值。

    参数的作用就是将元素转换为指定的类型,求平均值涉及到除法操作,结果一律为Double类型。

    方法:

     1 public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) {
     2     return new CollectorImpl<>(
     3             () -> new long[2],
     4             (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
     5             (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
     6             a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
     7 }
     8 public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) {
     9     return new CollectorImpl<>(
    10             () -> new long[2],
    11             (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
    12             (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
    13             a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
    14 }
    15 public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) {
    16     return new CollectorImpl<>(
    17             () -> new double[4],
    18             (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t); },
    19             (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
    20             a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID);
    21 }

    实例:

     1 public static void main(String[] args) {
     2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     4     double intAverage = list.stream().collect(Collectors.averagingInt(Integer::parseInt));
     5     System.out.println(intAverage);// 343.57142857142856
     6     double longAverage = list.stream().collect(Collectors.averagingLong(Long::parseLong));
     7     System.out.println(longAverage);// 343.57142857142856
     8     double doubleAverage = list.stream().collect(Collectors.averagingDouble(Double::parseDouble));
     9     System.out.println(doubleAverage);// 343.57142857142856
    10 }

    groupingBy方法

    生成一个拥有分组功能的Collector,有三个重载方法。

    方法:

     1 // 只需一个分组参数classifier,内部自动将结果保存到一个Map中,每个Map键的类型即classifier的结果类型,默认将组的元素保存在List中。
     2 public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
     3             Function<? super T, ? extends K> classifier) {
     4     return groupingBy(classifier, toList());
     5 }
     6 // 在上面方法的基础上增加了对流中元素的处理方式的Collector,默认是List。
     7 public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(
     8             Function<? super T, ? extends K> classifier,
     9             Collector<? super T, A, D> downstream) {
    10     return groupingBy(classifier, HashMap::new, downstream);
    11 }
    12 // 在第二个方法的基础上再添加了结果Map的生成方法,默认是HashMap。
    13 public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(
    14             Function<? super T, ? extends K> classifier,
    15             Supplier<M> mapFactory,
    16             Collector<? super T, A, D> downstream) {
    17     Supplier<A> downstreamSupplier = downstream.supplier();
    18     BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
    19     BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
    20         K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
    21         A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
    22         downstreamAccumulator.accept(container, t);
    23     };
    24     BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
    25     @SuppressWarnings("unchecked")
    26     Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
    27 
    28     if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
    29         return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
    30     }
    31     else {
    32         @SuppressWarnings("unchecked")
    33         Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
    34         Function<Map<K, A>, M> finisher = intermediate -> {
    35             intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
    36             @SuppressWarnings("unchecked")
    37             M castResult = (M) intermediate;
    38             return castResult;
    39         };
    40         return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
    41     }
    42 }

    实例:

     1 public static void main(String[] args) {
     2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
     3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
     4     Map<String, List<String>> groupByFirst = list.stream().collect(Collectors.groupingBy(e -> e.substring(0, 1)));
     5     System.out.println(groupByFirst);// {1=[123, 100], 2=[228, 250], 3=[345], 5=[521], 8=[838]}
     6     Map<String, Set<String>> groupByLast = list.stream().collect(Collectors.groupingBy(e -> e.substring(e.length() - 1), Collectors.toSet()));
     7     System.out.println(groupByLast);// {0=[100, 250], 1=[521], 3=[123], 5=[345], 8=[228, 838]}
     8     Map<Integer, Set<String>> groupByLength = list.stream().collect(Collectors.groupingBy(String::length, HashMap::new, Collectors.toSet()));
     9     System.out.println(groupByLength);// {3=[100, 123, 521, 345, 228, 838, 250]}
    10 }

    partitioningBy方法

    将流中的元素按照给定的校验规则的结果分为两个部分,放到Map中返回,键是Boolean类型,值为元素的列表List。

    方法:

     1 // 只需一个校验参数predicate。
     2 public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
     3     return partitioningBy(predicate, toList());
     4 }
     5 // 在上面方法的基础上增加了对流中元素的处理方式的Collector,默认的处理方法就是Collectors.toList()。
     6 public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
     7                                                 Collector<? super T, A, D> downstream) {
     8     BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
     9     BiConsumer<Partition<A>, T> accumulator = (result, t) ->
    10             downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
    11     BinaryOperator<A> op = downstream.combiner();
    12     BinaryOperator<Partition<A>> merger = (left, right) ->
    13             new Partition<>(op.apply(left.forTrue, right.forTrue),
    14                             op.apply(left.forFalse, right.forFalse));
    15     Supplier<Partition<A>> supplier = () ->
    16             new Partition<>(downstream.supplier().get(),
    17                             downstream.supplier().get());
    18     if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
    19         return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
    20     }
    21     else {
    22         Function<Partition<A>, Map<Boolean, D>> finisher = par ->
    23                 new Partition<>(downstream.finisher().apply(par.forTrue),
    24                                 downstream.finisher().apply(par.forFalse));
    25         return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
    26     }
    27 }

    实例:

    1 public static void main(String[] args) {
    2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
    3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
    4     Map<Boolean, List<String>> moreThan = list.stream().collect(Collectors.partitioningBy(e -> Integer.parseInt(e) > 300));
    5     System.out.println(moreThan);// {false=[123, 100, 228, 250], true=[521, 838, 345]}
    6     Map<Boolean, Set<String>> lessThan = list.stream().collect(Collectors.partitioningBy(e -> Integer.parseInt(e) < 300, Collectors.toSet()));
    7     System.out.println(lessThan);// {false=[521, 345, 838], true=[100, 123, 228, 250]}
    8 }
  • 相关阅读:
    设计模式复习-单例模式
    设计模式复习-组合模式
    设计模式复习-迭代器模式
    设计模式复习-备忘录模式
    PAT 1085 PAT单位排行 (Microsoft_zzt)
    PAT L1-034 点赞
    PAT L1-032 Left-pad
    PAT 甲级 1046 Shortest Distance
    PAT 甲级 1077 Kuchiguse
    PAT 甲级 1027 Colors in Mars
  • 原文地址:https://www.cnblogs.com/shamao/p/11828204.html
Copyright © 2011-2022 走看看