如何借助Collectors.counting() 来计算Java流中的元素

672 阅读4分钟

简介

一个流表示一个元素的序列,并支持不同类型的操作,以达到预期的结果。流的源头通常是一个集合或一个数组,数据从那里流出来。

流在几个方面与集合不同;最明显的是,流不是一个存储元素的数据结构。它们在本质上是功能性的,值得注意的是,对一个流的操作会产生一个结果,通常会返回另一个流,但不会修改其来源。

为了 "巩固 "这些变化,你一个流的元素收集回一个Collection

在本指南中,我们将看看如何借助Collectors.counting() 来计算Java流中的元素。

采集器和Stream.collect()

收集器代表了Collector 接口的实现,它实现了各种有用的缩减操作,例如将元素累积到集合中,根据特定的参数总结元素,等等。

所有预定义的实现都可以在Collectors 类中找到。

你也可以非常容易地实现你自己的收集器,并使用它来代替预定义的收集器--你可以用内置的收集器走得很远,因为它们涵盖了你可能想要使用它们的绝大多数情况。

为了能够在我们的代码中使用这个类,我们需要导入它。

import static java.util.stream.Collectors.*;

Stream.collect() 在流的元素上执行一个可变的还原操作。

可变还原操作在处理流中的元素时,将输入元素收集到一个可变容器中,比如Collection

Collectors.counting()的指南

Collectors.counting() 方法返回一个Collector ,接受类型为T 的元素,并对输入元素的数量进行计数。该方法的语法如下。

public static <T> Collector<T,?,Long> counting()

采集器的用法真的很简单--你只需把它夹在collect() 方法中。让我们创建一个有几个项目的 "杂货店购物清单",然后用Collectors.counting()计算清单中元素的数量

List<String> groceryList = Arrays.asList("apples", "milk", "meat", "eggs", "juice");
long result = groceryList.stream().collect(Collectors.counting());

System.out.println(result);

这样的结果是

5

注意: counting() 方法的返回类型始终是Long

作为下游收集器的Collectors.counting()

我们也可以在另一个接受下游采集器/函数的采集器中使用Collectors.counting() 作为下游函数。

Collectors.groupingBy() 或 是两个很好的例子,它们都常用于 。Collectors.groupingByConcurrent() Collectors.counting()

这是一个更常见的用例,而不仅仅是计算一个流中的元素数量,这是从一个集合中创建的。由于这是在自定义对象上最常做的,而不是原始类型或字符串--让我们定义一个简单的Book 模型。

public class Book {
    private String title;
    private String author;
    private int releaseYear;
    private int soldCopies;

    // Constructor, getters and setters

并让我们实例化一个BooksList

List<Book> books = Arrays.asList(
    new Book("The Fellowship of the Ring", "J.R.R. Tolkien", 1954, 30),
    new Book("The Hobbit", "J.R.R. Tolkien", 1937, 40),
    new Book("Animal Farm", "George Orwell", 1945, 37),
    new Book("Nineteen Eighty-Four", "George Orwell", 1949, 55),
    new Book("The Road to Wigan Pier", "George Orwell", 1937, 25),
    new Book("Lord of the Flies", "William Golding", 1954, 44)
);

假设我们拥有一家提供这些书的小书店,而soldCopies 是某个特定书的销售数量。我们想计算某个特定作者的书目卖出了多少份,35

这就需要根据soldCopies 字段过滤数据流,然后按作者分组,并计算与每个作者(组)相关的书籍。

由于groupingBy() 方法返回一个地图--我们的地图将由String (作者)和Long (计数的结果)组成。

Map<String, Long> soldCopiesStats = books.stream().filter(book -> book.getSoldCopies() > 35)
    .collect(Collectors.groupingBy(Book::getAuthor, Collectors.counting()));

System.out.println(soldCopiesStats);

我们把Collectors.counting() 作为Collectors.groupingBy() 的下游函数,这对获得一些漂亮的统计数据非常有用。

当我们运行这段代码时,我们得到以下结果

{J.R.R. Tolkien=1, William Golding=1, George Orwell=2}

结论

在本指南中,我们已经介绍了Collectors.counting() 方法。它在很多情况下都非常有用,因为元素的数量是一个有洞察力的指标。我们看了如何计算一个流中的元素数量,以及如何将其作为下游收集器与其他收集器一起使用,如groupingBy() ,以获得基于某些标准的元素的简单统计数字。