本文共 3371 字,大约阅读时间需要 11 分钟。
正如sql有很多种收集方式一样,用流收集数据也有很多种方式(= = 码字辛苦,点个赞) 1. 把流中的数据收集到一个List中 * List<Transaction> transactions= transactionStream.collect(Collectors.toList()); 2.计数(两种方式) * long howManyDishes=menu.stream().collect(Collectors.counting()); * long howManyDishes=menu.stream().count(); 3.查找最大值和最小值 * 使用Collectors.maxBy和Collectors.minBy两个收集器,来计算流中的最大或最小值。 这两个收集器接收一个Comparator参数来比较流中的元素。 eg: Comparator<Dish> dishCaloriesComParator = Comparator.comparingInt(Dish::getCalories); Optional<Optional> mostCalorieDish= menu.stream() .collect(maxBy(dishCaloriesComparator));(Optional是一个容器,可以避免安全性问题,后面会详细介绍) 4.汇总 * Collectors.summingInt(求和) 该方法接收一个把对象映射为求和所需int的函数,并返回一个收集器;该收集器在传递给普通的collect方法后即执行我们需要的汇总操作。 eg: int totalCalories=menu.stream().collect(summingInt(Dish::getCalories)); * Collectors.summingLong和 Collectors.summingDouble 用法同上 * Collectors.averagingInt(求平均) double avgCalories= menu.stream().collect(averagingInt(Dish::getCalories)); * Collectors.summariZing (同时得到总和、平均值、最大值和最小值) IntSummaryStatistics menuStatistics= menu.stream().collect(summarizingInt(Dish::getCalories)); 5.字符串连接 * joining joining工厂方法返回的收集器会把对流中每一个对象应用toString方法得到的所有字符串连接成一个字符串。 一种不接受参数,一种接收参数作为分界符 eg: * String shortMenu=menu.stream().map(Dish::getName).collect(joining()); * String shortMenu=menu.stream().map(Dish::getName).collect(joining(",")); 6.广义的规约汇总 * Collectors.reducing工厂方法 该方法是所有前面这些特殊情况的一般化。 * 求和 * 法1: int totalCalories=menu.stream().collect(reducing(0,Dish::getCalories,(i,j)-> i+j)); 注释:0代表起始值,仅仅是为了避免流中没有数据而发生无法预知的错误,Dish::getCalories是选值,最后的是操作. * 法2: 法1,我们说设置0是为了安全性考虑,那么Optional本身提供安全性,我们就可以这么做。 Optional<Dish> mostCalorieDish= menu.stream().collect(reducing( (d1,d2) ->d1.getCalories()>d2.getCalories() ? d1:d2 )); 一般来说,mostCalorieDish使用允许提供默认值的方法收集,入orElse或orElseGet来解开Optional中包含的值更安全。 7.分组 * groupingBy 给 groupingBy方法传递一个Function,它提取集合中该属性的对象,分组操作的结果是一个Map,把分组函数返回的值作为映射的键,把流中所有具有这个分类值的项目的列表作为对应的映射值。 eg: * 简单分组 Map<Dish.Type,List<Dish>> dishesByType= menu.stream().collect(groupingBy(Dish::getType)); * 非对象属性分组 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; }) ); * 多级分组 可以这么理解,先按外部分组,然后把外部分组的每一组进行内部分组,在后面可以看到,其实 groupingBy有两个参数,第二个参数就是每组的结果,就是把结果在分组 eg: Map<Dish.Type,Map<CaloricLevel,List<Dish>>> dishesByCaloricLevel = 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; })) ); * 按子组收集数据 * 更换收集结果 传递给第一个groupingBy的第二个收集器可以是任何类型,而不一定是另一个 groupingBy eg: Map<Dish.Type,Long> typesCount=menu.stream.collect(groupingBy(Dish::getType,counting())); 注释:其实groupingBy(f)实际上是groupingBy(f,toList())的简便写法。 Map<Dish.Type,Optional<Dish>> mostCalorieDish= menu.stream() .collect(groupingBy(Dish::getType,maxBy(comparingInt(Dish::getCalories)))); * 把收集器的结果转换为另一种类型 诚如这个例子,我们想要的是最小值,但是返回的却是Optional对象,我们需要做一些转换 Map<Dish.Type,Dish> mostCalorieDish= menu.stream() .collect(groupingBy(Dish::getType, //分类函数 collectingAndThen( maxBy(comparingInt(Dish::getCalories)), //包装后的收集器 Optional::get //转换函数 ))) 8.分区 分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称为分区函数 eg: Map<Boolean,List<Dish>> partitionedMenu= menu.stream().collect(partitioningBy(Dish::isVegetarian));转载地址:http://zmjqi.baihongyu.com/