文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java8中stream和functional interface怎么用

2023-05-30 22:18

关注

这篇文章主要为大家展示了“Java8中stream和functional interface怎么用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java8中stream和functional interface怎么用”这篇文章吧。

generate 与 Supplier

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

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

static <T> Stream<T> generate(Supplier<T> s);

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

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

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

Stream<UUID> 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<? 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<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 中所有元素之和了:

// 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 中的每一个字符串都变成大写:

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

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

// 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 中的偶数:

// 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 中的浮点数按绝对值的升序排列,并打印出来:

// 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 类型。

以上是“Java8中stream和functional interface怎么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯