美文网首页
Java8 Stream-2 用流收集数据

Java8 Stream-2 用流收集数据

作者: 巴巴11 | 来源:发表于2020-03-23 12:54 被阅读0次

    Collectors类提供的工厂方法(例如groupingBy)创建的收集器
    将流元素归约和汇总为一个值
    元素分组
    元素分区

    import static java.util.stream.Collectors.*;
    
    // 收集器用作高级归约
    List<Transaction> transactions =
        transactionStream.collect(Collectors.toList());
    
    Map<Currency, List<Transaction>> transactionsByCurrencies =
        transactions.stream().collect(groupingBy(Transaction::getCurrency));
    
    // 归约和汇总
    long howManyDishes = menu.stream().collect(Collectors.counting());
    long howManyDishes = menu.stream().count();
    
    // 查找流中的最大值和最小值
    Comparator<Dish> dishCaloriesComparator =
        Comparator.comparingInt(Dish::getCalories);
    Optional<Dish> mostCalorieDish =
        menu.stream()
            .collect(maxBy(dishCaloriesComparator));    
    
    // 汇总
    // Collectors.summingLong和Collectors.summingDouble方法的作用完全一样
    int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
    
    // 汇总不仅仅是求和;还有Collectors.averagingInt,连同对应的averagingLong和
    // averagingDouble可以计算数值的平均数
    double avgCalories =
        menu.stream().collect(averagingInt(Dish::getCalories));
    
    
    IntSummaryStatistics menuStatistics =
        menu.stream().collect(summarizingInt(Dish::getCalories));
    
    // 连接字符串
    String shortMenu = menu.stream().map(Dish::getName).collect(joining());
    String shortMenu = menu.stream().collect(joining());
    String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
    
    // 广义的归约汇总
    // Collectors.reducing工厂方法是所有这些特殊情况的一般化。
    int totalCalories = menu.stream()
        .collect(reducing(0, Dish::getCalories, (i, j) -> i + j));
    
    它需要三个参数。
    第一个参数是归约操作的起始值,也是流中没有元素时的返回值,所以很显然对于数值
    和而言0是一个合适的值。
    第二个参数函数,将菜肴转换成一个表示其所含热量的int。
    第三个参数是一个BinaryOperator,将两个项目累积成一个同类型的值。这里它就是对两个int求和。
    
    Optional<Dish> mostCalorieDish =
      menu.stream()
      .collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
    
    int totalCalories = menu.stream().collect(reducing(0,Dish::getCalories,Integer::sum));
    
    // 分组
    Map<Dish.Type, List<Dish>> dishesByType =
        menu.stream().collect(groupingBy(Dish::getType));
    
    public enum CaloricLevel { DIET, NORMAL, FAT }
    Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(
    groupingBy(dish -> {
    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
        else if (dish.getCalories() <= 700) return
        CaloricLevel.NORMAL;
        else return CaloricLevel.FAT;
    } ));
    
    // 多级分组
    Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
    menu.stream().collect(
    groupingBy(Dish::getType,
    groupingBy(dish -> {
    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
    else return CaloricLevel.FAT;
    } )
    )
    );
    
    Map<Dish.Type, Long> typesCount = menu.stream().collect(
    groupingBy(Dish::getType, counting()));
    
    Map<Dish.Type, Optional<Dish>> mostCaloricByType =
    menu.stream()
    .collect(groupingBy(Dish::getType,
    maxBy(comparingInt(Dish::getCalories))));
    
    Map<Dish.Type, Dish> mostCaloricByType =
    menu.stream()
    .collect(groupingBy(Dish::getType,
    collectingAndThen(
    maxBy(comparingInt(Dish::getCalories)),
    Optional::get)));
    
    Map<Dish.Type, Integer> totalCaloriesByType =
    menu.stream().collect(groupingBy(Dish::getType,
    summingInt(Dish::getCalories)));
    
    Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
    menu.stream().collect(
    groupingBy(Dish::getType, mapping(
    dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
    else return CaloricLevel.FAT; },
    toSet() )));
    
    Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
    menu.stream().collect(
    groupingBy(Dish::getType, mapping(
    dish -> { if (dish.getCalories() <= 400) return CaloricLevel.DIET;
    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
    else return CaloricLevel.FAT; },
    toCollection(HashSet::new) )));
    
    // 分区
    Map<Boolean, List<Dish>> partitionedMenu =
    menu.stream().collect(partitioningBy(Dish::isVegetarian));
    List<Dish> vegetarianDishes = partitionedMenu.get(true);
    
    Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType =
    menu.stream().collect(
    partitioningBy(Dish::isVegetarian,
    groupingBy(Dish::getType)));
    
    Map<Boolean, Dish> mostCaloricPartitionedByVegetarian =
    menu.stream().collect(
    partitioningBy(Dish::isVegetarian,
    collectingAndThen(
    maxBy(comparingInt(Dish::getCalories)),
    Optional::get)));
    
    
    

    Collectors类的静态工厂方法


    image.png
    image.png

    Collector接口包含了一系列方法,为实现具体的归约操作(即收集器)提供了范本。
    已经看过了Collector接口中实现的许多收集器,例如toList或groupingBy。
    这也意味着,可以为Collector接口提供自己的实现,从而自由地创建自定义归约操作。

    package java.util.stream;
    public interface Collector<T, A, R> {
    Supplier<A> supplier();
    BiConsumer<A, T> accumulator();
    Function<A, R> finisher();
    BinaryOperator<A> combiner();
    Set<Characteristics> characteristics();
    }
    

    自定义收集器

    package com.hw;
    
    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 MyCollector<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 (l1, l2) -> {
                l1.addAll(l2);
                return l1;
            };
        }
    
        @Override
        public Function<List<T>, List<T>> finisher() {
            return Function.identity();
        }
    
        @Override
        public Set<Characteristics> characteristics() {
            return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT));
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Java8 Stream-2 用流收集数据

          本文链接:https://www.haomeiwen.com/subject/vdjiyhtx.html