放下的,放不下的,最终都该属于自己的路,不必过分留恋与不舍
- 从外部迭代到内部迭代。
通常在操作集合时,我们会使用到for循环(这里暂只说for这个操作集合的方法)。
例如,我们要找出一个集合中,来自London的艺术家有几个。
private static void withOut(List<ArtistEntity> artistArr) {
int count = 0;
for(ArtistEntity ae : artistArr) {
if(ae.isFrom("London")) {
count ++;
}
}
System.out.println("来自伦敦的艺术家有" + count + "个");
}
尽管这样做是可以达到目的的,但是每次迭代都需要写for (xxx xx:xxx) {}等这样的样板代码,java8以后,出现了一个新的方式,内部迭代。
首先内部迭代是将集合转换成一个 Stream,xxArray.stream(),这个方法返回的是一个Stream接口
private static void inside(List<ArtistEntity> artistArr) {
long count = artistArr.stream().
filter(artist -> artist.isFrom("London")).count();
System.out.println("来自伦敦的艺术家有" + count + "个");
}
Stream是用函数式编程方式在集合类上进行复杂操作的工具。 上面这段例子,实际上可以分解成下面两个步骤。
- 找出所有来自伦敦的艺术家
- 计算出他们的人数
每种操作都对应Stream接口的一个方法。为了找出来自伦敦的艺术家。需要对Stream对象进行过滤,filter。过滤在这里指“只保留通过某项测试的对象”,这里就是 contry是London的艺术家。该测试返回true或者false。由于Stream的API的函数式编程风格,因此,这里并没有改变集合的内容,而是描述出Stream里的内容,count()方法计算指定Stream里包含了多少个对象。 如此,语法简洁了很多,并且按照人的思维模式去描述代码,也是很容易一眼看上去就做了那些事儿。
2.惰性求值和及早求值。
artistArr.stream().filter(artist -> artist.isFrom("London"))
上述这段代码,实际上并未作出什么实际性的工作,filter只刻画出了一个Stream,但没有产生新的集合。像filter 这样只描述一个Stream,最终没有产生新集合的方法,称为惰性求值方法;而count这样最终会从 Steam产生值的方法叫做及早求值法。 下面做个小测试。
不产生新的集合,只产生一个Stream
artistArr.stream().filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
});
运行这一段代码,是不会有任何输出的,因为filter只刻画出了一个Stream,但没有产生新的集合。
接下来,在调用一次count方法
//这段调用了count方法,终止了操作的流。因此就有值输出了,
artistArr.stream().filter(artist -> {
System.out.println(artist.getName());
return artist.isFrom("London");
}).count();
输出结果如下;
join
joyy
jone
小总结:
- 使用流操作并且有效的掌握了惰性求值和及早求值,才能更有效的进行计算。例如,如果要找出工资低于3000块的第一个员工,不需要讲所有元素都进行比较,只要找出第一个匹配的元素就够了。这也意味着可以在集合类上级联多种操作,但迭代仅仅只有一次。
- 判断一个操作是惰性求值还是及早求值很简单;只需看它的返回值。如果返回值是Stream,那么就是惰性求值;如果返回值是另一个值或为空,那么就是及早求值。使用这些操作的理想方式就是形成一个惰性求值链,最后用一个及早求值的操作返回想要的结果,这正是它的设计合理之处。计数的示例也是这样运行的,但这只是简单的情况,包含了两个步骤。
整个过程和建造者模式有共通之处。建造者模式使用一系列操作设置属性和配置,最后调用一个build方法,这是对象才真正被创建。
最后送给自己一句话
生命需要不断的努力,但是不要太急
网友评论