Java 流处理之收集器详解

Java 流处理之收集器详解

Java 8 引入了一个新的 Stream API,其中的收集器(Collector)是 Java 8 可以处理流(Stream)中数据的一个关键工具。收集器是指将流中元素转换成不同形式的操作。在本文中,我们将详细介绍 Java 中的收集器。

收集器的基本概念

Java 8 提供了 22 个预定义的收集器。这些收集器和终止操作结合使用来对流进行收集。Java 中的收集器具有以下基本特征:

  • 可转换为 List、Set 或 Map 等集合数据结构;
  • 可以限制结果集的长度;
  • 可以通过分组、分区等方式对结果进行分组;
  • 可以自定义将流中的元素聚合成一个集合的方式。

收集器分类

Java 中的收集器主要分为以下几类:

1. 转换收集器

转换收集器可以将流中的元素转换为指定类型的集合。Java 提供的转换收集器有以下几种:

  • toList():将流转换为 List 集合;
  • toSet():将流转换为 Set 集合;
  • toMap():将流转换为 Map,Key 和 Value 由 map 接收的两个函数推断出来。

以下是 toList() 和 toSet() 的示例代码:

List<String> list = Arrays.asList("Java", "Python", "C++");
List<String> result = list.stream().collect(Collectors.toList());
System.out.println(result); // [Java, Python, C++]

Set<String> set = Arrays.asList("Java", "Python", "C++", "Java").stream().collect(Collectors.toSet());
System.out.println(set); // [Java, Python, C++]

2. 分组收集器

分组收集器可以将流中的元素按条件分组。Java 提供的分组收集器有以下几种:

  • groupingBy():按照分组条件进行分组;
  • partitioningBy():按照分区条件进行分区。

以下是 groupingBy() 的示例代码:

class Product {
    private String name;
    private String category;
    // 省略 getters 和 setters 方法
}

List<Product> productList = Arrays.asList(
    new Product("A", "Category1"), new Product("B", "Category2"),
    new Product("C", "Category1"), new Product("D", "Category2"));

Map<String, List<Product>> result = productList.stream().collect(Collectors.groupingBy(Product::getCategory));
System.out.println(result);

// 输出:
// {Category1=[Product{name='A', category='Category1'}, 
// Product{name='C', category='Category1'}], 
// Category2=[Product{name='B', category='Category2'}, 
// Product{name='D', category='Category2'}]}

3. 聚合收集器

将流中的元素聚合成一个值。Java 提供的聚合收集器有以下几种:

  • reducing():对流中的元素进行聚合,最终返回一个 Optional;
  • summarizingInt()、summarizingDouble()、summarizingLong():将流中的元素转换为 Int、Double 或 Long 类型,然后进行汇总操作。

以下是 reducing() 和 summarizingInt() 的示例代码:

// 使用 reducing() 计算元素的总和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().collect(Collectors.reducing(Integer::sum));
System.out.println(sum); // Optional[15]

// 使用 summarizingInt() 计算元素的平均值、最大值、最小值、总和等
List<Integer> numbers2 = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics stats = numbers2.stream().collect(Collectors.summarizingInt(Integer::intValue));
System.out.println(stats.getAverage()); // 3.0
System.out.println(stats.getMax()); // 5
System.out.println(stats.getMin()); // 1
System.out.println(stats.getSum()); // 15

收集器的使用

1. 如何定义自定义收集器

我们可以通过实现 Collector 接口来定义自己的收集器。Collector 接口定义了四个方法:

  • supplier():提供一个空的累加器(即初始容器),用于累加收集的元素;
  • accumulator():将元素 T 添加到累加器 A 中,并且在添加完后,累加器必须按原有顺序无副作用的处理前一个累加器,然后返回一个新的累加器;
  • combiner():将 A1 和 A2 两个累加器合并成一个新的累加器,通常与accumulator() 方法相反,其中 A2 代表 accumulator() 方法返回的新容器,A1 代表旧容器;
  • finisher():对最终容器进行转换,例如将累加器转换成期望的返回类型,或对其进行最终的变换。

下面是示例代码:

class Person {
    private String name;
    private int age;
    // 省略 getters 和 setters 方法
}

class PersonStatistics {
    int count;
    int totalAge;
    double averageAge;

    public PersonStatistics() {
        this.count = 0;
        this.totalAge = 0;
        this.averageAge = 0.0;
    }

    public void accept(Person person) {
        count++;
        totalAge += person.getAge();
        averageAge = (double) totalAge / (double) count;
    }

    public PersonStatistics combine(PersonStatistics other) {
        count += other.count;
        totalAge += other.totalAge;
        averageAge = (double) totalAge / (double) count;
        return this;
    }

    public void finish() {
        // do nothing
    }

    public double getAverageAge() {
        return this.averageAge;
    }

    // 省略 toString() 方法
}

class PersonCollector implements Collector<Person, PersonStatistics, PersonStatistics> {

    @Override
    public Supplier<PersonStatistics> supplier() {
        return PersonStatistics::new;
    }

    @Override
    public BiConsumer<PersonStatistics, Person> accumulator() {
        return PersonStatistics::accept;
    }

    @Override
    public BinaryOperator<PersonStatistics> combiner() {
        return PersonStatistics::combine;
    }

    @Override
    public Function<PersonStatistics, PersonStatistics> finisher() {
        return personStatistics -> {
            personStatistics.finish();
            return personStatistics;
        };
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }
}

List<Person> personList = Arrays.asList(
        new Person("Hank", 33),
        new Person("Charlie", 31),
        new Person("Emily", 26),
        new Person("Michael", 58)
);

PersonStatistics personStatistics = personList.stream().collect(new PersonCollector());
System.out.println(personStatistics);

输出结果:

PersonStatistics{count=4, totalAge=148, averageAge=37.0}

2. 如何使用自定义收集器

要使用自定义收集器,需要将其传递给 Stream 的 collect() 方法。以下是示例代码:

List<Person> personList = Arrays.asList(
        new Person("Hank", 33),
        new Person("Charlie", 31),
        new Person("Emily", 26),
        new Person("Michael", 58)
);

PersonStatistics personStatistics = personList.stream().collect(new PersonCollector());
System.out.println(personStatistics);

输出结果:

PersonStatistics{count=4, totalAge=148, averageAge=37.0}

小结

Java 中的收集器是处理流中数据的重要工具。本文主要介绍了收集器的基本概念、分类、使用方法和自定义方法。在实际的开发过程中,需要根据具体业务需求来选择不同的收集器。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java 流处理之收集器详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Ubuntu如何轻松编译openJDK详解

    下面是“Ubuntu如何轻松编译openJDK详解”的完整攻略。 准备工作: 本地安装 Ubuntu 系统。 安装 JDK(Java Development Kit)并配置环境变量。 编译 OpenJDK: 步骤一:获取源代码 访问 OpenJDK 官网,选择需要的版本进行下载。例如,我选择下载 JDK 11 的源代码压缩包。(示例1) 将下载的压缩包解压缩…

    Java 2023年5月26日
    00
  • java中Hibernate面试知识点整理

    Java中Hibernate面试知识点整理 什么是Hibernate? Hibernate是一个基于Java语言的ORM(对象关系映射)框架,简单来说就是将Java对象和数据库表进行映射,使得开发人员可以将精力放在业务逻辑的开发上,而不用去关注数据库相关的细节。 Hibernate的主要特点 简化了数据持久化的开发工作 数据库无关性,可以支持多种主流数据库 …

    Java 2023年5月20日
    00
  • Java多线程Callable接口实现代码示例

    下面是Java多线程Callable接口实现的完整攻略步骤: 1.什么是Callable接口 Callable和Runnable类似,都是用来创建线程的接口,但是Callable的call()方法有返回值,并且可以抛出异常。 public interface Callable<V> { V call() throws Exception; } 2…

    Java 2023年5月19日
    00
  • Spring Boot超详细讲解请求处理流程机制

    Spring Boot超详细讲解请求处理流程机制 Spring Boot请求处理流程概述 在Spring Boot中,请求处理流程一般可以分为以下几个步骤: 浏览器发送HTTP请求。 请求到达本地服务器,并被Spring Boot框架接收。 Spring Boot对请求进行预处理,包括对请求头、请求参数、cookie进行解析,以及对请求URL进行映射。 根据…

    Java 2023年5月19日
    00
  • Java面试题冲刺第八天–Spring框架2

    Java面试题冲刺第八天–Spring框架2 本文将详细讲解Java面试题冲刺第八天–Spring框架2的完整攻略,包括Spring框架的概述、Spring框架的核心模块、Spring框架的优点、Spring框架的示例说明等。 Spring框架的概述 Spring框架是一个轻量级的Java开发框架,它提供了一系列的工具和框架,用于简化Java开发过程中的…

    Java 2023年5月18日
    00
  • Java利用TreeUtils工具类实现列表转树

    下面是Java利用TreeUtils工具类实现列表转树的完整攻略。 1.准备工作 在进行列表转树操作前,需要先准备好列表数据。假设列表中每个元素都具有一个唯一标识符id和一个父元素标识符parentId,我们可以封装一个类来表示列表元素: public class TreeNode { private String id; private String pa…

    Java 2023年5月20日
    00
  • JAVA的Random类的用法详解

    JAVA的Random类的用法详解 java.util.Random类是一个用于生成伪随机数的类,它在Java中的使用非常广泛。在今天的攻略中,我们将详细讲解Random类的各种用法,以帮助您更好地掌握它的使用方法。 生成随机数 首先,我们来看下如何使用Random类来生成随机数。 随机数的类型可以是整数或浮点数。 生成整数随机数 生成整数随机数的方法是使用…

    Java 2023年5月19日
    00
  • java Date和SimpleDateFormat时间类详解

    Java Date 和 SimpleDateFormat 时间类详解 Java Date 和 SimpleDateFormat 是 Java 日期/时间处理中最常用的类,可以方便地进行日期和时间格式化、解析和计算。本文将详细讲解 Java Date 和 SimpleDateFormat 的使用方法,包括创建 Date 对象、格式化日期和时间、解析字符串为 D…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部