- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java8中stream和functional interface的配合使用详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
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.
1
|
static
<T> Stream<T> generate(Supplier<T> s);
|
Supplier 的方法 get() 在每次调用时都返回一个 T 的对象。因为 get() 方法不接收任何参数,所以使用 generate 时,代码总是会写成类似 () -> returnValue 的样子.
另外,由于 get() 可以被调用无限多次,因此通过 generate 生成的 stream 也是无限长的,必要时可以通过 .limit() 截取前若干个元素.
例如,如果想获得一个无限长的随机 UUID 序列,可以使用下面的方法:
1
|
Stream<UUID> infiniteUUIDStream = Stream.generate(() -> UUID.randomUUID());
|
想要获取诸如 1 ~ 10 这样的序列也是可行的,但需要一个 helper class 记录当前状态,这里就不提供案例了.
forEach 与 Consumer 。
知道了如何生成 stream,也要知道如何消费它。既然 stream 可以从 Collection 来,那么最后应该也能变成 Collection,这就是 collect() 的功劳了。collect() 接收一个 Collector 作为参数,返回从 stream 生成的 Collection 对象。不过这个 Collector 不是函数式接口,所以不属于本文的重点。下面着重讲解的是 forEach 方法.
1
|
void
forEach(Consumer<?
super
T> action);
|
forEach 与函数式接口 Consumer 配合工作,Consumer 的 void accept(T t) 方法就是来消费 stream 中的各个元素的。因为 accept 接收单个元素 T 作为参数,forEach 会写成 e -> statement 的形式,其中 statement 不返回任何值.
比如,逐行打印 stream 中的每一个元素,就可以写作:
1
|
stream.forEach(e -> System.out.println(e));
|
或者通过方法引用进一步简化:
1
|
stream.forEach(System.out::println);
|
reduce 与 BinaryOperator 。
除了 forEach 这种吞噬元素的终结型操作以外,使用 stream 中的元素还有两种常见的模式。第一种依旧是终结型操作:整合所有的元素,最后返回一个单一的值,我们把这个操作称作 reduce。第二种则是过程性操作,它让每个元素都有自己对应的返回值,之后重组成为新的 stream,以便下一步继续利用。我们把第二种操作称为 map。把刚刚提及的这两个操作结合起来,就是大名鼎鼎的 MapReduce 了(误).
reduce 与一种特殊的函数式接口搭配使用,它叫 BinaryOperator。BinaryOperator<T> 的原型是 BiFunction<T, T, T>,那这个 BiFunction 又是怎么回事呢?原来,BiFunction<T, U, R> 是一个宽泛的函数式接口,它的方法 R apply(T t, U u) 接受类型为 T 和 U 的两个参数,并返回一个类型为 R 的值。如果 T U R 这三者的类型相同,就可以写作 BiFunction<T, T, T>。因为这种用法尤其常见,于是它有了自己专属的名字,即 BinaryOperator<T>。最常见的 BinaryOperator 当属二元算术操作,我们熟知的加减乘除都属于这个范畴.
讲解 reduce 时最常见的例子就是求一个 stream 中所有元素之和了:
1
2
|
// stream: Stream<Integer>
Optional<Integer> sum = stream.reduce((a, b) -> a + b);
|
我们可以看出,reduce 方法的特征是 (a, b) -> returnValue。它返回的结果是 Optional,我们可以用 .isPresent() 查看是否为空值;当值不为空时,用 .get() 获取数据.
map 与 Function 。
map 或许是 stream 中使用最为广泛的一个操作了。与 reduce 涉及的 BiFunction 不同,与 map 配套使用的函数式接口是略为简单的 Function。它同样是一个宽泛的函数式接口,同时也是函数式接口最著名的代表。Function<T, R> 的方法 R apply(T t) 接受一个类型为 T 的参数,并返回一个类型为 R 的值。map 所做的事情,就是把这个 Function 应用于 stream 中的每一个元素,以得到一个新的全部由 R 组成的 stream.
比如说,把一个 stream 中的每一个字符串都变成大写:
1
2
|
// original: Stream<String>
Stream<String> transformed = original.map(e -> e.toUpperCase());
|
map 方法的特征是 e -> returnValue。正如我们之前用过的 System.out::println 一样,这里也可以使用方法引用简化代码,只要引用的方法符合 map 预期的类型即可:传入一个 T 参数,返回一个 R 值.
1
2
|
// original: Stream<String>
Stream<String> transformed = original.map(String::toUpperCase);
|
filter 与 Predicate 。
介绍了 forEach,reduce 和 map 这些重量级的操作,下面我们来处理一个尴尬的问题:如果这个 stream 中有我们不想要的元素怎么办?答案是使用 filter 把他们踢出去.
与 filter 搭配使用的函数式接口是 Predicate。Predicate<T> 的方法 boolean test(T t) 接受一个类型为 T 的参数,并返回 true 或是 false。我们可以认为 Predicate<T> 就是特异化的 Function<T, boolean>,因为它使用得足够广泛,所以自立门户成为一套单独的接口.
在下面的例子中,程序只打印 stream 中的偶数:
1
2
|
// stream: Stream<Integer>
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<T> 使用 int compare(T o1, T o2) 方法比较两个 T 类型的对象。排序正是通过比较对象之间的相对大小实现的.
接下来的例子将 stream 中的浮点数按绝对值的升序排列,并打印出来:
1
2
3
4
5
6
7
|
// stream: Stream<Double>
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 类型.
总结 。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://bitmingw.com/2017/11/04/java-stream-with-functional-interface/ 。
最后此篇关于Java8中stream和functional interface的配合使用详解的文章就讲到这里了,如果你想了解更多关于Java8中stream和functional interface的配合使用详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!