Documentation

The Java™ Tutorials
Hide TOC
Aggregate Operations聚合操作
Trail: Collections

Lesson: Aggregate Operations课程:聚合操作

Note: To better understand the concepts in this section, review the sections Lambda Expressions and Method References.注意:为了更好地理解本节中的概念,请查看Lambda表达式方法引用部分

For what do you use collections? 您使用集合的目的是什么?You don't simply store objects in a collection and leave them there. 您不能简单地将对象存储在集合中并将它们留在那里。In most cases, you use collections to retrieve items stored in them.在大多数情况下,您使用集合检索其中存储的项。

Consider again the scenario described in the section Lambda Expressions. 再次考虑lambda表达式节中描述的场景。Suppose that you are creating a social networking application. 假设您正在创建一个社交网络应用程序。You want to create a feature that enables an administrator to perform any kind of action, such as sending a message, on members of the social networking application that satisfy certain criteria.您希望创建一个功能,使管理员能够对满足特定条件的社交网络应用程序的成员执行任何类型的操作,例如发送消息。

As before, suppose that members of this social networking application are represented by the following Person class:与前面一样,假设此社交网络应用程序的成员由以下Person类表示:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;
    
    // ...

    public int getAge() {
        // ...
    }

    public String getName() {
        // ...
    }
}

The following example prints the name of all members contained in the collection roster with a for-each loop:以下示例使用for-each循环打印集合roster中包含的所有成员的名称:

for (Person p : roster) {
    System.out.println(p.getName());
}

The following example prints all members contained in the collection roster but with the aggregate operation forEach:以下示例使用聚合操作forEach打印集合forEach中包含的所有成员:

roster
    .stream()
    .forEach(e -> System.out.println(e.getName());

Although, in this example, the version that uses aggregate operations is longer than the one that uses a for-each loop, you will see that versions that use bulk-data operations will be more concise for more complex tasks.尽管在本例中,使用聚合操作的版本比使用for-each循环的版本长,但您将看到,对于更复杂的任务,使用批量数据操作的版本将更简洁。

The following topics are covered:涵盖以下主题:

Find the code excerpts described in this section in the example BulkDataOperationsExamples.在示例BulkDataOperationsExamples中查找本节中描述的代码摘录。

Pipelines and Streams管道和流

A pipeline is a sequence of aggregate operations. 管道是一系列聚合操作。The following example prints the male members contained in the collection roster with a pipeline that consists of the aggregate operations filter and forEach:以下示例使用由聚合操作filterforEach组成的管道打印集合roster中包含的男性成员:

roster
    .stream()
    .filter(e -> e.getGender() == Person.Sex.MALE)
    .forEach(e -> System.out.println(e.getName()));

Compare this example to the following that prints the male members contained in the collection roster with a for-each loop:将此示例与以下示例进行比较,该示例使用for-each循环打印集合roster中包含的男性成员:

for (Person p : roster) {
    if (p.getGender() == Person.Sex.MALE) {
        System.out.println(p.getName());
    }
}

A pipeline contains the following components:管道包含以下组件:

The following example calculates the average age of all male members contained in the collection roster with a pipeline that consists of the aggregate operations filter, mapToInt, and average:以下示例使用由聚合操作filtermapToIntaverage组成的管道计算集合roster中包含的所有男性成员的平均年龄:

double average = roster
    .stream()
    .filter(p -> p.getGender() == Person.Sex.MALE)
    .mapToInt(Person::getAge)
    .average()
    .getAsDouble();

The mapToInt operation returns a new stream of type IntStream (which is a stream that contains only integer values). mapToInt操作返回IntStream类型的新流(该流仅包含整数值)。The operation applies the function specified in its parameter to each element in a particular stream. 该操作将其参数中指定的函数应用于特定流中的每个元素。In this example, the function is Person::getAge, which is a method reference that returns the age of the member. 在本例中,函数是Person::getAge,它是返回成员年龄的方法引用。(Alternatively, you could use the lambda expression e -> e.getAge().) (或者,您可以使用lambda表达式e -> e.getAge()Consequently, the mapToInt operation in this example returns a stream that contains the ages of all male members in the collection roster.因此,本例中的mapToInt操作返回一个流,其中包含roster名册中所有男性成员的年龄。

The average operation calculates the average value of the elements contained in a stream of type IntStream. average操作计算IntStream类型的流中包含的元素的平均值。It returns an object of type OptionalDouble. 它返回OptionalDouble类型的对象。If the stream contains no elements, then the average operation returns an empty instance of OptionalDouble, and invoking the method getAsDouble throws a NoSuchElementException. 如果流不包含任何元素,那么average操作将返回OptionalDouble的空实例,并且调用方法getAsDouble将抛出NoTouchElementExceptionThe JDK contains many terminal operations such as average that return one value by combining the contents of a stream. JDK包含许多终端操作,例如通过组合流的内容返回一个值的averageThese operations are called reduction operations; see the section Reduction for more information.这些操作称为缩减操作;有关更多信息,请参阅减少部分。

Differences Between Aggregate Operations and Iterators聚合操作和迭代器之间的差异

Aggregate operations, like forEach, appear to be like iterators. 聚合操作,如forEach,看起来像迭代器。However, they have several fundamental differences:然而,它们有几个基本区别:


Previous page: Previous Lesson
Next page: Reduction