vlambda博客
学习文章列表

掌握Java8 函数式编程(一)-Stream

    java8现在目前是国内各大主流公司内服役的版本,随着行业内技术升级(内卷)地加剧,不仅面试中对java8的要求越来越高,而且实际开发中使用java8为开发带来便捷性、高效性也是有目共睹,让我们一起来学习一下!


    java8中新增了很多特性,分别是Lambda、方法引用、默认方法、新工具、Stream、DateTimeApi、Optional、Nashron-js引擎。增加这些特性旨在帮助开发人写出更好的代码,其中对核心库的改造--集合类Api和流Stream是非常关键部分,流的使用使程序员在更高的抽象层次对集合进行处理。

    

    从外部迭代到内部迭代

    

    在使用集合类时,通用模式为在集合上进行迭代处理,然后处理返回每个元素,如:



    代码尽管操作可行,但是存在如下几个问题,每次迭代时都要写类似样板代码,将for循环改造成并行方式需要改每个for循环,很是麻烦。除此之外,由于for循环的样板代码模糊了代码本意,上述代码也无法清晰的传达程序操作的意图,当面对嵌套循环的庞大代码时,前述情形更加恶劣。分析其原理可见,for循环实质封装了迭代,首先调用Iterator产生Iterator对象,然后显式调用Iterator对象的hashNext和next完成数据下标移动,此处理为外部迭代,本质上为一种串行化操作,将行为和方法混为一谈。


 

    另一种为内部迭代,即使用流的方式,如下图代码:



    先调用stream()方法获取内部迭代接口Stream(Stream是用函数式编程方式在集合类上进行复杂操作的工具),然后进行两部处理


    ·先找出所有的等于西岐的元素:


strLst.stream().filter(x-> x.equals("西岐"))


    ·计算个数:


strLst.stream().filter(x-> x.equals("西岐")).count();

    

    由于 Stream API 的函数式编 程风格,我们并没有改变集合的内容,而是描述出 Stream 里的内容;


    实现机制

    传统处理使用了一个for循环,那么前述分为两步操作的处理是否需要两次循环?不是的,实际只进行了一次循环。java的stream里一些方法返回的对象不是一个新集合,而是创建新集合的配方,如


strLst.stream().filter(x-> x.equals("朝歌"));


    该代码未做实质性工作,最终也不会产生新集合,此类型称为惰性求值方法,类似前文count方法最红从stream中产生值的方法叫做及早求值方法。


    判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。如果返回值是 Stream, 那么是惰性求值;如果返回值是另一个值或为空,那么就是及早求值。使用这些操作的理 想方式就是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果,此种处理逻辑共通于建造者模式,建造者模式使用一系列操作设置属性和配置,最后调 用一个 build 方法,这时,对象才被真正创建

    

    为什么要区分惰性求值和及早求值?


    是因为在开发中有些情况只有在对需要什么样的结果和操作有了更多了解之后,才能更有效率地进行计算。例如,如果要找出大于 10 的第一个数字,那么并不需要和所有元素去做比较,只要找出第一个匹配的元素就够了。这也意味着 可以在集合类上级联多种操作,但迭代只需一次。

    

    以上为今天分享的函数式编程里流的简单介绍,后续的推送文章将继续讲解常用的流操作、各个流操作的常用整合,以及多次调用流和高阶函数相关的处理。(了解其他端开发知识点可以私信,我提前安排文章内容的排版处理)


敬请各位看官订阅关注!