美文网首页
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 用流收集数据

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

  • java8用流收集数据

    收集器简介 Collector 函数式编程相对于指令式编程的一个主要优势:你只需要指出希望的结果“做什么”,而不用...

  • java8用流收集数据

    用流收集数据 汇总 查找最大值和最小值 连接字符串 广义的归约汇总 reducing需要说那个参数: 1.起始值 ...

  • Java8笔记(2)

    Java8笔记(2) 用流收集数据 收集器 函数式编程相对于指令式编程的一个主要优势:你只需指出希望的结果——“做...

  • 用流收集数据

    找出流中最大和最小元素 汇总 字符串连接joining工厂方法返回的收集器会把对流中每一个对象应用tostring...

  • 用流收集数据

    归约和总结 分组 分区 收集器接口 可以不用实现Collector进行自定义收集

  • 用流收集数据

    Collection、Collector和Collect的区别: Collection:Collection是集合...

  • 从Java 8 stream 到 rxjava, 记录一次数据流

    在java8之前, 一直都是用guava中的Iterables和FluentIterables来处理数据流。 ja...

  • Dart Stream

    Stream Dart中的流概念和Java8中的流概念非常相似。 在同步的世界里:一个数据可以用一个对象表示,众多...

  • Java 8 知识归纳(一)—— 流 与 Lambda

    一、Java8 的三个编程概念 流处理从输入流中一个一个读取数据项,然后以同样的方式将数据项写入输出流。 用行为参...

网友评论

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

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