The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
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 以下示例使用for-each循环打印集合roster
with a for-each loop: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
中查找本节中描述的代码摘录。
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
:filter
和forEach
组成的管道打印集合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 将此示例与以下示例进行比较,该示例使用for-each循环打印集合roster
with a for-each loop:roster
中包含的男性成员:
for (Person p : roster) { if (p.getGender() == Person.Sex.MALE) { System.out.println(p.getName()); } }
A pipeline contains the following components:管道包含以下组件:
A source: This could be a collection, an array, a generator function, or an I/O channel. 源:可以是集合、数组、生成器函数或I/O通道。In this example, the source is the collection 在本例中,源是集合roster
.roster
。
Zero or more intermediate operations. 零个或多个中间操作。An intermediate operation, such as 中间操作(如filter
, produces a new stream.filter
)生成新流。
A stream is a sequence of elements. 流是一系列元素。Unlike a collection, it is not a data structure that stores elements. 与集合不同,它不是存储元素的数据结构。Instead, a stream carries values from a source through a pipeline. 相反,流通过管道携带来自源的值。This example creates a stream from the collection 本例通过调用方法roster
by invoking the method stream
.stream
从集合roster
创建流。
The filter
operation returns a new stream that contains elements that match its predicate (this operation's parameter). filter
操作返回一个新流,其中包含与其谓词(此操作的参数)匹配的元素。In this example, the predicate is the lambda expression 在本例中,谓词是lambda表达式e -> e.getGender() == Person.Sex.MALE
. e -> e.getGender() == Person.Sex.MALE
。It returns the boolean value 如果对象true
if the gender
field of object e
has the value Person.Sex.MALE
. e
的性别字段的值为Person.Sex.MALE
,则返回布尔值true
。Consequently, the 因此,本例中的filter
operation in this example returns a stream that contains all male members in the collection roster
.filter
操作返回一个包含集合roster
中所有男性成员的流。
A terminal operation. 终端操作。A terminal operation, such as 终端操作(如forEach
, produces a non-stream result, such as a primitive value (like a double value), a collection, or in the case of forEach
, no value at all. forEach
)会生成非流结果,如原语值(如双精度值)、集合,或者在forEach
中根本没有值。In this example, the parameter of the 在本例中,forEach
operation is the lambda expression e -> System.out.println(e.getName())
, which invokes the method getName
on the object e
. forEach
操作的参数是lambda表达式e -> System.out.println(e.getName())
,它调用对象e
上的方法getName
。(The Java runtime and compiler infer that the type of the object (Java运行时和编译器推断对象e
is Person
.)e
的类型为Person
。)
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
:filter
、mapToInt
和average
组成的管道计算集合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 (或者,您可以使用lambda表达式e -> e.getAge()
.) 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
将抛出NoTouchElementException
。The JDK contains many terminal operations such as JDK包含许多终端操作,例如通过组合流的内容返回一个值的average
that return one value by combining the contents of a stream. average
。These operations are called reduction operations; see the section Reduction for more information.这些操作称为缩减操作;有关更多信息,请参阅减少部分。
Aggregate operations, like 聚合操作,如forEach
, appear to be like iterators. forEach
,看起来像迭代器。However, they have several fundamental differences:然而,它们有几个基本区别:
They use internal iteration他们使用内部迭代: Aggregate operations do not contain a method like :聚合操作不包含类似next
to instruct them to process the next element of the collection. next
的方法来指示它们处理集合的下一个元素。With internal delegation, your application determines what collection it iterates, but the JDK determines how to iterate the collection. 通过内部委托,应用程序决定迭代哪个集合,但JDK决定如何迭代集合。With external iteration, your application determines both what collection it iterates and how it iterates it. 通过外部迭代,您的应用程序可以确定它迭代的集合和迭代方式。However, external iteration can only iterate over the elements of a collection sequentially. 但是,外部迭代只能按顺序迭代集合的元素。Internal iteration does not have this limitation. 内部迭代没有这个限制。It can more easily take advantage of parallel computing, which involves dividing a problem into subproblems, solving those problems simultaneously, and then combining the results of the solutions to the subproblems. 它可以更容易地利用并行计算,这涉及到将问题划分为子问题,同时解决这些问题,然后将子问题的解决方案的结果组合起来。See the section Parallelism for more information.有关更多信息,请参阅并行性一节。
They process elements from a stream: Aggregate operations process elements from a stream, not directly from a collection. 它们处理来自流的元素:聚合操作处理来自流的元素,而不是直接来自集合。Consequently, they are also called stream operations.因此,它们也被称为流操作。
They support behavior as parameters: You can specify lambda expressions as parameters for most aggregate operations. 它们支持作为参数的行为:您可以将lambda表达式指定为大多数聚合操作的参数。This enables you to customize the behavior of a particular aggregate operation.这使您能够自定义特定聚合操作的行为。