Java函数式编程之如何使用流Stream
这篇文章主要讲解了“Java函数式编程之如何使用流Stream”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java函数式编程之如何使用流Stream”吧!
创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于成都网站设计、网站建设、外贸网站建设、安化网络推广、小程序定制开发、安化网络营销、安化企业策划、安化品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联公司为所有大学生创业者提供安化建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com
Listwords = Arrays.asList("hello","world"); List chars = words.stream() .flatMap(word -> Stream.of(word.split(""))) .collect(Collectors.toList()); Jdk8中新增的特性旨在帮助程序员写出更好的代码,其中对核心类库的改进是很关键的一部分。对核心类库的改进主要包括集合类的API和新引入的流(Stream)。流使程序员得以站在更高的抽象层次上对集合进行操作。
1.什么是流(Stream)?
Stream是特定类型的对象形成的一个队列并支持聚合操作。 Java中的Stream并不会存储元素,而是按需计算。流的来源可以是集合,数组,I/O channel, 产生器generator 等。聚合操作类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。和以前的Collection操作不同, Stream操作还有两个基础的特征:Pipelining中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道,如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
Listlist = Arrays.asList("a", "b", "c", "d", null); List filtered = list.stream().filter(e -> Objects.nonNull(e)).collect(Collectors.toList()); long count = list.parallelStream().filter(e -> Objects.nonNull(e)).count();
2.内部迭代
Java程序员在使用集合时,一个通用的模式时在集合上进行迭代,在迭代过程中处理每一个元素并返回处理结果。通常代码时这样的:
Listlist = Arrays.asList(1, 2, 3, 4, 5); int sum = 0; Iterator iterator = list.iterator(); while (iterator.hasNext()) { sum += iterator.next(); } System.out.println(sum);
这段代码本身没什么问题就写起来有点麻烦,就其背后原理来看其实就是一个封装了迭代的语法糖,首先调用iterator方法产生一个新的Iterator对象进而控制整个迭代过程,这就是外部迭代。
然而外部迭代的问题在于首先,很难抽象出后续提到的复杂操作,另外从本质上来讲只是一种串行化操作。总体来看使用for循环会将行为和方法混为一谈。另一种方法是内部迭代,和调用iterator()作用一样使用stream()方法,该方法不是返回一个控制迭代的Iterator对象,而是返回内部迭代中的相应接口:Stream。示例如下:
Listlist = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Integer sum = list.stream().filter(e -> e > 5).reduce(0, Integer::sum); System.out.println(sum);
3.实现机制
通常在Java 中调用一个方法计算机会随即执行操作:比如,System.out.println("hello world!")会在终端上输出一条信息。Stream里的一些方法略有不同,它们虽是普通Java方法但是返回的Stream对象并不是一个新的集合,而是创建新集合的配方。
list.stream().filter(e -> e > 5);
上述代码并未做什么实际性的工作,filter只是刻画出了Stream但是并没有产生新的集合,像filter这样只描述Stream,最终不产生新集合的方法惰性求值方法,而像sum()这样最终从Stream产出值的方法叫做及早求值方法。如果在filter方法中添加一条输出语句就会比较清楚的看出差异。
Listlist = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); list.stream().filter(e -> { System.out.println(e); return e > 5; });
如果将上述语句添加一个及早求值方法就可以看到集合中的元素被打印出来。
Listlist = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); list.stream().filter(e -> { System.out.println(e); return e > 5; }).findFirst();
判断一个操作是惰性求值还是及早求值很简单,只要返回值是Stream那么是惰性求值。使用这些操作的理想方式就是形成一个惰性求值链,最后用一个及早求值的操作返回想要的结果,这正是他的合理之处。那为什么要区分惰性求值和及早求值呢?原因很简单只需要一次迭代就可以得到全部结果,例如 :上述代码只需要找到第一个大于5的数而不需要比较所有集合元素。
4.常用的流操作
为了更好的学习Stream,我们接下来学习一些常用的stream操作。
filter
如果需要在遍历集合元素时清洗非法元素可以使用filter方法,我们在上述讨论过程中已经使用过该方法。filter接收一个函数作为参数,该函数使用lambda表达式表示,如果被清洗元素符合预期则返回true,其实看源码会发现这个lambda表达式是我们之前讲过的 Predicate
collect
这个方法是由Stream生成一个List,是一个及早求值操作。Jdk8中借鉴了很多Scala的设计思想,Stream的of方法可以用来生成一个新的Stream,我们来看下边的一个例子。
Listlist = Stream.of("a", "b", "c","d","e").collect(Collectors.toList());
map
map函数是用来讲一个类型转换为另外一种类型,参数同样是一个lambda表达式对应我们之前讲过的 Function
Listlist = Stream.of("a", "b", "c").map(e -> e.toUpperCase()).collect(Collectors.toList()); System.out.println(list);
flatMap
和map类似,不同的是其每个元素转换得到的是Stream对象,最终会把转换得到的多个Stream连接成一个Stream。
Listwords = Arrays.asList("hello","world"); List chars = words.stream() .flatMap(word -> Stream.of(word.split(""))) .collect(Collectors.toList());
上述代码我们可以得到输出结果 :[h, e, l, l, o, w, o, r, l, d],如果将flatMap换成map会发现我们得到了一个List
max和min
和之前讲的函数不同,这两个方法要求参数是一个比较器 Comparator
Integer min = Stream.of(1,2,3,4,5).min(Integer::compare).get();System.out.println(min);Integer max = Stream.of(1,2,3,4,5).max(Integer::compare).get();System.out.println(max);
reduce
该函数可以实现从一组值中生成一个值,在上述例子中用到的 sum、max、min本质上都是reduce操作。Stream的求和结果每一步都将Stream中的元素累加至accumulator,遍历至Stream中的最后一个元素时,accumulator的值就是所有元素的和。我们看如下例子
Integer sum = Stream.of(1, 2, 3, 4, 5).reduce(0, (acc, e) -> acc + e); System.out.println(sum);
这段代码如果你对scala熟悉那么会很容易理解,acc作为累加器存储了中间计算结果,整个lambda函数本质上是我们之前讲过的BinaryOperator。
感谢各位的阅读,以上就是“Java函数式编程之如何使用流Stream”的内容了,经过本文的学习后,相信大家对Java函数式编程之如何使用流Stream这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
当前名称:Java函数式编程之如何使用流Stream
本文链接:http://scjbc.cn/article/pjsedo.html