java stream API初探(二):为了高效

本文介绍StreamAPI如何在遍历和搜索操作中优化性能,避免不必要的元素处理,减少耗时操作的执行次数。通过具体示例解释了中间操作与终止操作的概念,以及延迟执行机制如何帮助提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在尝试使用stream api后,如果不了解stream api背后的优化机制,肯定会产生担心,觉得它中看不中用。本文就是为了消解这类担忧而写。
好的api不仅让你用得方便,还要让你用的放心。stream api已经进行了效率上的优化,能满足多数情况下所需的高效。
比如当你遍历序列,搜寻特定值时,希望一旦得到结果则立即返回,而不是遍历全部值。有时,判断元素满足特定条件的过程十分复杂,更应该尽可能减少判断次数。注重程序效率的你,一定会在普通的循环中进行条件判断加以剪枝,对这些情况进行优化。也许在你看来,具体场景下的优化措施各异,而stream api 通过关注其中的公共点,不露痕迹地完成繁琐的优化任务。

我们先通过一个具体的例子,说明stream api如何进行优化,顺带引入它的一些概念。

下面的例子,是搜寻许多学生中满足特定条件的学生。

class Student{
    private int age;

    boolean fun(){
        //极为耗时的操作,例如查询数据库等
        //进行一些判断,返回布尔值
    }

    int age(){
        return age;
    }
}
List<Student> students = new ArrayList<Student>();
//填充students,假设students中包含100万个student对象
students.stream()
        .filter(Student::fun)
        .map(stu->return stu.age())
        .findAny();
//注意这里的findAny

在上面的代码中,目的是为了找出能使fun()返回true的Student对象,并返回这个student的age属性。假设Student::fun方法是极为耗时的,并且序列包含海量对象。那么这种时候,我们要避免处理不必要的元素,找到满足条件的学生就执行后续操作。
考察程序执行过程,一种显而易见的处理方式是,程序先对所有对象进行了filter,再取出过滤后的student对象的age属性,最后选择其中任意一个值。
但是这个过程存在极大浪费,更加合理的过程应该是,在遍历的同时,每访问一个student对象,就执行fun方法,如果返回true,则取其age属性值。这样就可能减少fun的执行次数,对元素的访问次数。stream api正是这样做的。

那么它是如何实现这点的呢?通过了解两个概念来回答这个问题。

1.intermediate and terminal operation
中间操作与终止操作。
前面一篇文章已经提到过stream中的pipeline,意指多个操作的组合。一个pipeline中可以有任意个中间操作,但最后的必须是终止操作,且只有一个终止操作。这并非语法上的要求。但假如一个pineline只包含中间操作,那么它没有任何实际效果,即任何操作都没有执行。只有当终止操作存在时,操作才能真正执行。
举例说明:

//符合语法,但无任何意义
students.stream().filter(Student::fun());

上面代码中的fun方法,一次都不会执行。你可以在fun中加入输出语句进行验证。这是因为,filter是一个中间操作(intermediate operation)。要想使这句话产生实际效果,末尾需要加一个终止操作,例如findAny,max。
在stream api文档中,会明确指出某个操作属于中间操作或终止操作。如果你把这些操作全部了解一遍,你会发现它们的返回值或是含义是有规律可循的。中间操作只能返回一个Stream对象,含义是对原有stream进行某种映射得到新的stream;终止操作往往返回一个具体对象,含义是从stream中推出某个结果。

2.lazy stream
一个pineline的执行过程,是每当从原stream中取出一个元素,就令它通过所有中间操作,直到终止操作。如果终止操作的执行,需要其它元素参与,如max,min(需要和其余元素比较),则进行等待。如果终止操作的执行不需要其他元素的参与,如findAny,则直接返回结果。

回到对效率问题的解答。在上面示例中,从stream中取出一个元素时,首先经过filter,map,最终到达findAny。因为findAny的执行不需要其它元素的参与,所以就直接得到结果,避免了多余的访问。

以上是stream api对pipeline执行过程的设计。除此之外,我们常用的优化方法是,将串行变为并行。而stream api的底层实现也考虑到了这一点,这是你从表面完全看不到的。

结语:
当这些设计呈现在我面前时,除了解除我对效率的担忧,还让我感到抽象的力量。从低层角度看,每个问题的优化策略都是不同的,但是stream api可以通过提取其中的共同点,解决其中的关键问题,在高层角度解决了大部分情况的优化问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值