java8 Stream stream().filter()进行迭代及实现机制

13 篇文章 0 订阅
1 篇文章 0 订阅

系列文章目录



前言

本文为java8函数式编程读书笔记。

提示:以下是本篇文章正文内容,下面案例可供参考

一、使用迭代

1.外部迭代

先看一个示例:如果要计算从伦敦来的艺术家的人数,要使用外部迭代方式,通常我们会这么写

int count = 0;
for (Artist artist : allArtists) {
	if (artist.isFrom("London")) 
	{ 
		count++; 
	} 
}

如上代码,for 循环其实是一个封装了迭代的语法糖,我们在这里多花点时间, 看看它的工作原理。首先调用 iterator 方法,产生一个新的 Iterator 对象,进而控制整 个迭代过程,这就是外部迭代。迭代过程通过显式调用 Iterator 对象的 hasNext 和 next 方法完成迭代,展开后的代码是这个样子滴

int count = 0; 
Iterator<Artist> iterator = allArtists.iterator();
while(iterator.hasNext()) {
	 Artist artist = iterator.next();
	if (artist.isFrom("London")) { 
	count++; 
	} 
}

在这里插入图片描述

2.内部迭代

如下代码:
首先要注意 stream() 方法的调用,它和上面调用 iterator() 的作用一样。该方法不是返回一个控制迭代的 Iterator 对象,而是返 回内部迭代中的相应接口:Stream

long count = allArtists.stream() .filter(artist -> artist.isFrom("London")) .count();

使用后的方法调用流程
在这里插入图片描述
具体来讲其大致可分为两步简单的操作:

  • 找出所有来自伦敦的艺术家;
  • 计算他们的人数。

每种操作都对应 Stream 接口的一个方法。为了找出来自伦敦的艺术家,需要对 Stream 对 象进行过滤:filter。过滤在这里是指“只保留通过某项测试的对象”。测试由一个函数完 成,根据艺术家是否来自伦敦,该函数返回 true 或者 false。由于 Stream API 的函数式编 程风格,我们并没有改变集合的内容,而是描述出 Stream 里的内容。count() 方法计算给 定 Stream 里包含多少个对象。

二、实现机制

整个过程被分解为两种更简单的操作:过滤和计数,看似有化简为繁之嫌—— 外部迭代中只含一个 for 循环,两种操作是否意味着需要两次循环?事实上,类库设计精妙, 只需对艺术家列表迭代一次。
通常,在 Java 中调用一个方法,计算机会随即执行操作:比如,System.out.println (“Hello World”); 会在终端上输出一条信息。Stream 里的一些方法却略有不同,它们虽是 普通的 Java 方法,但返回的 Stream 对象却不是一个新集合,而是创建新集合的配方。

1.惰性求值方法

示例1:只过滤,不计数

allArtists.stream() .filter(artist -> artist.isFrom("London"));

这行代码并未做什么实际性的工作,filter 只刻画出了 Stream,但没有产生新的集合。像 filter 这样只描述 Stream,最终不产生新集合的方法叫作惰性求值方法

如果在过滤器中加入一条 println 语句,来输出艺术家的名字,就能轻而易举地看出其中的不 同。下面代码加入了输出语句。运行这段代码,程序不会输出任何信息!

示例2:由于使用了惰性求值,没有输出艺术家的名字

allArtists.stream() 
			.filter(artist -> { 
				System.out.println(artist.getName());
				return artist.isFrom("London"); 
				});

2.及早求值方法

示例:计算来自伦敦的艺术家人数

long count = allArtists.stream() .filter(artist -> artist.isFrom("London")) .count();

上述代码中 像count 方法这样 最终会从 Stream 产生值的方法叫作及早求值方法
所以更改上一节的 示例2,末尾加上count方法艺术家的名 字就会被输出。

long count = allArtists.stream() 
						.filter(artist -> {
						 	System.out.println(artist.getName());
							return artist.isFrom("London"); })
						.count();

3.如何判断方法类型

判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。如果返回值是 Stream, 那么是惰性求值;如果返回值是另一个值或为空,那么就是及早求值。使用这些操作的理 想方式就是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果,这正是 它的合理之处。计数的示例也是这样运行的,但这只是最简单的情况:只含两步操作。 整个过程和建造者模式有共通之处。建造者模式使用一系列操作设置属性和配置,最后调 用一个 build 方法,这时,对象才被真正创建。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值