聚合操作
你使用集合做什么?你不可能简单地将对象存储在集合中并将它们留在那里,在大多数情况下,使用集合检索存储在其中的项。
再次考虑Lambda表达式小节中描述的场景,假设你正在创建一个社交网络应用程序,你希望创建一个功能,使管理员能够对满足某些条件的社交网络应用程序的成员执行任何类型的操作,例如发送消息。
如前所述,假设这个社交网络应用程序的成员由以下Person类表示:
public class Person { public enum Sex { MALE, FEMALE } String name; LocalDate birthday; Sex gender; String emailAddress; // ... public int getAge() { // ... } public String getName() { // ... } }
下面的示例使用for-each循环打印集合roster中包含的所有成员的名称:
for (Person p : roster) { System.out.println(p.getName()); }
下面的示例打印集合roster中包含的所有成员,但使用集合操作forEach:
roster .stream() .forEach(e -> System.out.println(e.getName());
尽管在本例中,使用聚合操作的版本比使用for-each循环的版本要长,但是你将看到,对于更复杂的任务,使用批量数据操作的版本将更加简洁。
在示例BulkDataOperationsExamples中找到本节中描述的代码摘录。
管道和流管道是聚合操作的序列,下面的示例打印集合roster中包含的男性成员,其中包含由聚合操作filter和forEach组成的管道:
roster .stream() .filter(e -> e.getGender() == Person.Sex.MALE) .forEach(e -> System.out.println(e.getName()));
将此示例与下面的示例进行比较,下面的示例打印集合roster中包含的男性成员,并使用for-each循环:
for (Person p : roster) { if (p.getGender() == Person.Sex.MALE) { System.out.println(p.getName()); } }
管道包含以下组件:
源:可以是集合、数组、生成器函数或I/O通道,在本例中,源是集合roster。
零或多个中间操作,中间操作(如filter)生成一个新的流。
流是元素的序列,与集合不同,它不是存储元素的数据结构,相反,流通过管道携带来自源的值,这个示例通过调用方法stream从集合roster创建一个流。
filter操作返回一个新的流,其中包含与其predicate匹配的元素(此操作的参数),在本例中,predicate是lambda表达式e -> e.getGender() == Person.Sex.MALE。如果对象e的gender字段的值为Person.Sex.MALE,则返回布尔值true,因此,本例中的filter操作返回一个包含集合roster中所有男性成员的流。
一个终端操作,终端操作(如forEach)生成非流结果,如原始值(如双精度值)、集合,或者在forEach的情况下,根本没有值。在本例中,forEach操作的参数是lambda表达式e -> System.out.println(e.getName()),调用对象e上的getName方法(Java运行时和编译器推断对象e的类型是Person)。
下面的示例计算集合roster中包含的所有男性成员的平均年龄,其中管道由聚合操作filter、mapToInt和average组成:
double average = roster .stream() .filter(p -> p.getGender() == Person.Sex.MALE) .mapToInt(Person::getAge) .average() .getAsDouble();
mapToInt操作返回一个类型为IntStream的新流(这是一个只包含整数值的流),该操作将其参数中指定的函数应用于特定流中的每个元素,在这个例子中,函数是Person::getAge,它是一个方法引用,返回成员的年龄(或者,你可以使用lambda表达式e -> e. getage())。因此,本例中的mapToInt操作返回一个流,其中包含集合roster中所有男性成员的年龄。
average操作计算类型IntStream中包含的元素的平均值,它返回一个OptionalDouble类型的对象,如果流不包含元素,则average操作返回OptionalDouble的空实例,调用getAsDouble方法将抛出NoSuchElementException。JDK包含许多终端操作,比如average,通过组合流的内容返回一个值,这些操作称为归纳操作。
聚合操作和迭代器之间的区别像forEach这样的聚合操作看起来像迭代器,然而,它们有几个根本的区别:
它们使用内部迭代:聚合操作不包含像next这样的方法来指示它们处理集合的下一个元素,使用内部委托,应用程序决定迭代什么集合,但是JDK决定如何迭代集合,使用外部迭代,你的应用程序将确定它迭代哪些集合以及如何迭代。然而,外部迭代只能按顺序迭代集合的元素,内部迭代没有这种限制,它可以更容易地利用并行计算,这涉及到将一个问题划分为子问题,同时解决这些问题,然后将子问题的解的结果组合起来。
它们处理来自流的元素:聚合操作处理流中的元素,而不是直接从集合中聚合,因此,它们也称为流操作。
它们支持将行为作为参数:可以将lambda表达式指定为大多数聚合操作的参数,这使你能够自定义特定聚合操作的行为。
上一篇:SortedMap接口文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75569.html
Java™ 教程 Java教程是为JDK 8编写的,本页面中描述的示例和实践没有利用在后续版本中引入的改进。 Java教程是希望使用Java编程语言创建应用程序的程序员的实用指南,其中包括数百个完整的工作示例和数十个课程,相关课程组被组织成教程。 覆盖基础知识的路径 这些教程以书籍的形式提供,如Java教程,第六版,前往Amazon.com购买。 入门 介绍Java技术和安装Java开发软件并使用...
Collection接口 Collection表示一组称为其元素的对象,Collection接口用于传递需要最大通用性的对象集合,例如,按照惯例,所有通用集合实现都有一个带有Collection参数的构造函数,此构造函数(称为转换构造函数)初始化新集合以包含指定集合中的所有元素,无论给定集合的子接口或实现类型如何,换句话说,它允许你转换集合的类型。 例如,假设你有一个Collection c,它可...
Lambda表达式 匿名类的一个问题是,如果匿名类的实现非常简单,例如只包含一个方法的接口,那么匿名类的语法可能看起来不实用且不清楚,在这些情况下,你通常会尝试将功能作为参数传递给另一个方法,例如当有人单击按钮时应采取的操作,Lambda表达式使你可以执行此操作,将功能视为方法参数,或将代码视为数据。 上一节匿名类向你展示了如何在不给它命名的情况下实现基类,虽然这通常比命名类更简洁,但对于只有一个...
集合介绍 本节介绍Java集合框架,在这里,你将了解集合是什么以及它们如何使你的工作更轻松、程序更好,你将了解构成Java集合框架的核心元素 — 接口、实现、聚合操作和算法。 集合 — 有时称为容器 — 只是一个将多个元素组合到一个单元中的对象,集合用于存储、检索、操作和传递聚合数据。通常,它们代表形成自然组的数据项,例如扑克牌(卡片集合)、邮件文件夹(信件集合)或电话目录(名称到电话号码的映射)...
摘要:接着我们将数据流按照单词字段即号索引字段做分组,这里可以简单地使用方法,得到一个以单词为的数据流。得到的结果数据流,将每秒输出一次这秒内每个单词出现的次数。最后一件事就是将数据流打印到控制台,并开始执行最后的调用是启动实际作业所必需的。 本文转载自 Jark’s Blog ,作者伍翀(云邪),Apache Flink Committer,阿里巴巴高级开发工程师。 本文将从开发环境准备、创建 ...
阅读 2431·2021-11-24 10:29
阅读 2616·2021-09-24 09:48
阅读 5682·2021-09-22 15:56
阅读 3138·2021-09-06 15:00
阅读 2648·2019-08-30 15:54
阅读 724·2019-08-30 13:48
阅读 2819·2019-08-30 11:17
阅读 3402·2019-08-29 11:20