热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java8中stream和functionalinterface的配合使用详解

这篇文章主要给大家介绍了关于Java8中stream和functionalinterface配合使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java8具有一定的参考学习价值,需要的朋友们下面来一起看看吧。

前言

Java 8 提供了一组称为 stream 的 API,用于处理可遍历的流式数据。stream API 的设计,充分融合了函数式编程的理念,极大简化了代码量。

大家其实可以把Stream当成一个高级版本的Iterator。原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!(这个秘籍,一般人我不告诉他:))

我们来讲解如何将常用的 stream API 与相应的 functional interface (函数式接口)配合使用,达成数据处理的目的。

类似于困扰哲学家们数千年的三大问题,关于 stream 我们也有三个疑团需要解开:它从哪里来?它能做什么?它会变成什么?

generate 与 Supplier

stream 最常见的来源是 Collection。Collection 是一组可遍历元素的抽象容器。它有两大类实现:不允许重复元素的 Set 和允许重复的 List。只要在某个 Collection 对象后面加上 .stream() 或者 .parallelStream() 就可以得到相应的 stream 了。

如果没有现成的 Collection,或者 Collection 太大根本存不下,还有什么办法可以生成 stream 么?如果知道生成 stream 中每个元素的算法,就可以无中生有造出一个 stream 来。这里用到的是方法 Stream.generate(),它依赖于一个函数式接口 Supplier。

static  Stream generate(Supplier s);

Supplier 的方法 get() 在每次调用时都返回一个 T 的对象。因为 get() 方法不接收任何参数,所以使用 generate 时,代码总是会写成类似 () -> returnValue 的样子。

另外,由于 get() 可以被调用无限多次,因此通过 generate 生成的 stream 也是无限长的,必要时可以通过 .limit() 截取前若干个元素。

例如,如果想获得一个无限长的随机 UUID 序列,可以使用下面的方法:

Stream infiniteUUIDStream = Stream.generate(() -> UUID.randomUUID());

想要获取诸如 1 ~ 10 这样的序列也是可行的,但需要一个 helper class 记录当前状态,这里就不提供案例了。

forEach 与 Consumer

知道了如何生成 stream,也要知道如何消费它。既然 stream 可以从 Collection 来,那么最后应该也能变成 Collection,这就是 collect() 的功劳了。collect() 接收一个 Collector 作为参数,返回从 stream 生成的 Collection 对象。不过这个 Collector 不是函数式接口,所以不属于本文的重点。下面着重讲解的是 forEach 方法。

void forEach(Consumer<&#63; super T> action);

forEach 与函数式接口 Consumer 配合工作,Consumer 的 void accept(T t) 方法就是来消费 stream 中的各个元素的。因为 accept 接收单个元素 T 作为参数,forEach 会写成 e -> statement 的形式,其中 statement 不返回任何值。

比如,逐行打印 stream 中的每一个元素,就可以写作:

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

或者通过方法引用进一步简化:

stream.forEach(System.out::println);

reduce 与 BinaryOperator

除了 forEach 这种吞噬元素的终结型操作以外,使用 stream 中的元素还有两种常见的模式。第一种依旧是终结型操作:整合所有的元素,最后返回一个单一的值,我们把这个操作称作 reduce。第二种则是过程性操作,它让每个元素都有自己对应的返回值,之后重组成为新的 stream,以便下一步继续利用。我们把第二种操作称为 map。把刚刚提及的这两个操作结合起来,就是大名鼎鼎的 MapReduce 了(误)。

reduce 与一种特殊的函数式接口搭配使用,它叫 BinaryOperator。BinaryOperator 的原型是 BiFunction,那这个 BiFunction 又是怎么回事呢?原来,BiFunction 是一个宽泛的函数式接口,它的方法 R apply(T t, U u) 接受类型为 T 和 U 的两个参数,并返回一个类型为 R 的值。如果 T U R 这三者的类型相同,就可以写作 BiFunction。因为这种用法尤其常见,于是它有了自己专属的名字,即 BinaryOperator。最常见的 BinaryOperator 当属二元算术操作,我们熟知的加减乘除都属于这个范畴。

讲解 reduce 时最常见的例子就是求一个 stream 中所有元素之和了:

// stream: Stream
Optional sum = stream.reduce((a, b) -> a + b);

我们可以看出,reduce 方法的特征是 (a, b) -> returnValue。它返回的结果是 Optional,我们可以用 .isPresent() 查看是否为空值;当值不为空时,用 .get() 获取数据。

map 与 Function

map 或许是 stream 中使用最为广泛的一个操作了。与 reduce 涉及的 BiFunction 不同,与 map 配套使用的函数式接口是略为简单的 Function。它同样是一个宽泛的函数式接口,同时也是函数式接口最著名的代表。Function 的方法 R apply(T t) 接受一个类型为 T 的参数,并返回一个类型为 R 的值。map 所做的事情,就是把这个 Function 应用于 stream 中的每一个元素,以得到一个新的全部由 R 组成的 stream。

比如说,把一个 stream 中的每一个字符串都变成大写:

// original: Stream
Stream transformed = original.map(e -> e.toUpperCase());

map 方法的特征是 e -> returnValue。正如我们之前用过的 System.out::println 一样,这里也可以使用方法引用简化代码,只要引用的方法符合 map 预期的类型即可:传入一个 T 参数,返回一个 R 值。

// original: Stream
Stream transformed = original.map(String::toUpperCase);

filter 与 Predicate

介绍了 forEach,reduce 和 map 这些重量级的操作,下面我们来处理一个尴尬的问题:如果这个 stream 中有我们不想要的元素怎么办?答案是使用 filter 把他们踢出去。

与 filter 搭配使用的函数式接口是 Predicate。Predicate 的方法 boolean test(T t) 接受一个类型为 T 的参数,并返回 true 或是 false。我们可以认为 Predicate 就是特异化的 Function,因为它使用得足够广泛,所以自立门户成为一套单独的接口。

在下面的例子中,程序只打印 stream 中的偶数:

// stream: Stream
stream.filter(e -> e % 2 == 0).forEach(System.out::println);

可以看出,由于 Predicate 是一种特异的 Function,所以 filter 方法的特征与 map 在外观上如出一辙。不过 filter 要保证 e -> returnValue 中的 returnValue 是一个 boolean,否则编译会报错。

sorted 与 Comparator

最后来看看 stream 中非常强大的 sorted 方法,它允许我们自定义比较规则对 stream 中的元素排序。与 sorted 搭配的函数式接口是 Comparator,Comparator 使用 int compare(T o1, T o2) 方法比较两个 T 类型的对象。排序正是通过比较对象之间的相对大小实现的。

接下来的例子将 stream 中的浮点数按绝对值的升序排列,并打印出来:

// stream: Stream
stream.sorted((a, b) -> {
 double diff = a - b;
 if (diff <0) return -1;
 else if (diff > 0) return 1;
 else return 0;
 }).forEach(System.out::println);

不难看出,sorted 方法的特征与 reduce 比较相似,都是 (a, b) -> returnValue 的结构,但是要保证 returnValue 是 int 类型。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。


推荐阅读
  • 全面解读Apache Flink的核心架构与优势
    Apache Flink作为大数据处理领域的新兴力量,凭借其独特的流处理能力和高效的批处理性能,迅速获得了广泛的关注。本文旨在深入探讨Flink的关键技术特点及其应用场景,为大数据处理提供新的视角。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 本文详细介绍了 Flink 和 YARN 的交互机制。YARN 是 Hadoop 生态系统中的资源管理组件,类似于 Spark on YARN 的配置方式。我们将基于官方文档,深入探讨如何在 YARN 上部署和运行 Flink 任务。 ... [详细]
  • 2018年3月31日,CSDN、火星财经联合中关村区块链产业联盟等机构举办的2018区块链技术及应用峰会(BTA)核心分会场圆满举行。多位业内顶尖专家深入探讨了区块链的核心技术原理及其在实际业务中的应用。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 大数据时代的机器学习:人工特征工程与线性模型的局限
    本文探讨了在大数据背景下,人工特征工程与线性模型的应用及其局限性。随着数据量的激增和技术的进步,传统的特征工程方法面临挑战,文章提出了未来发展的可能方向。 ... [详细]
  • 深入浅出:Hadoop架构详解
    Hadoop作为大数据处理的核心技术,包含了一系列组件如HDFS(分布式文件系统)、YARN(资源管理框架)和MapReduce(并行计算模型)。本文将通过实例解析Hadoop的工作原理及其优势。 ... [详细]
  • 本文详细介绍了W3C标准盒模型和IE传统盒模型的区别,探讨了CSS3中box-sizing属性的使用方法及其在布局中的重要性。通过实例分析,帮助读者更好地理解和应用这一关键概念。 ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • 初探Hadoop:第一章概览
    本文深入探讨了《Hadoop》第一章的内容,重点介绍了Hadoop的基本概念及其如何解决大数据处理中的关键挑战。 ... [详细]
author-avatar
主播新鲜看连
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有