资讯专栏INFORMATION COLUMN

「Java 8 函数式编程」读书笔记——流

qpwoeiru96 / 2884人阅读

摘要:本文是函数式编程第三章的读书笔记,章名为流。正确使用表达式明确要达成什么转化,而不是说明如何转化没有副作用只通过函数的返回值就能充分理解函数的全部作用函数不会修改程序或外界的状态获取值而不是变量避免使用数组逃过的追杀,应该考虑优化逻辑

本文是「Java 8 函数式编程」第三章的读书笔记,章名为流。本章主要介绍了外部迭代与内部迭代以及常用的高阶函数。

外部迭代与内部迭代 外部迭代

过去我们要对一个List进行迭代时,往往会采用如下方式:

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

而这种方法的原理,其实是先调用iterator方法,然后再迭代,等效于如下代码:

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

这样的迭代方式,把迭代的控制权交给了iterator对象,让其控制整个迭代过程,这就叫做外部迭代

外部迭代需要我们自己编写迭代的控制代码,显得十分繁琐。特别是对于Map对象,繁琐到我都不想给出例子。

外部迭代将行为和方法混为一谈,难以对代码进行重构操作。

内部迭代

与之相对的就是内部迭代了。内部迭代就是把迭代的控制权交给了集合本身,让集合自己实现相应的迭代,而调用者并不需要关心如何迭代

要使用内部迭代,需要使用Java 8中新增的接口Stream。而集合框架都已经包含了一个stream()方法,用于获得Stream对象。

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

这个例子就是使用的内部迭代。先获取stream对象,然后调用filter方法过滤,最后统计符合条件的个数。

实现机制

Java中调用一个方法,通常会立即执行操作。然而Stream里的一些方法却不太一样,它们返回的对象不是新的集合,而是创建新集合的配方。我们通过一个例子说明:

Stream names = Stream.of("Bryant", "Jordon", "James")
  .filter(name -> {
    System.out.println(name);
    return name.length() == 6;
  });
System.out.println("counting");
System.out.println(names.count());

最终会得到如下输出:

counting
Bryant
Jordon
James
2

出现这样的结果,原因是

filter这样的方法,只会描述Stream,最终不会产生新集合的方法叫做惰性求值方法

count这样会从Stream中产生值或集合等结果的方法叫做及早求值方法

判断一个操作是惰性求值还是及早求值,只需要看它的返回值

如果返回值是Stream,则是惰性求值

返回的是一个值或null,则是及早求值

在对集合使用流操作时,使用惰性求值方法形成一个惰性求值的链,最后用及早求值方法得到结果,而集合只需要迭代一次。

常用流操作

collect:及早求值,常用于生成List Map或其他复杂的数据结构

map:惰性求值,将一种类型的数据转换成另一种类型,将一个流中的值转化成一个新的流,类似于Hadoop里的map

filter:惰性求值,过滤不符合条件的元素

flatMap:惰性求值,类似于map,只是Function参数的返回值限定为Stream,用于连接多个Stream成为一个Stream

max & min:及早求值,reduce方法的特例,返回Optional(第四章介绍)对象

reduce:及早求值,从一组值中生成一个值,类似于Hadoop中的reduce

高阶函数

高阶函数接收一个函数作为参数,或者返回一个函数的函数。

正确使用Lambda表达式

明确要达成什么转化,而不是说明如何转化

没有副作用:

只通过函数的返回值就能充分理解函数的全部作用

函数不会修改程序或外界的状态

获取值而不是变量(避免使用数组逃过JVM的追杀,应该考虑优化逻辑)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66602.html

相关文章

  • Java 8 函数编程读书笔记——数据并行化

    摘要:限制编写并行流,存在一些与非并行流不一样的约定。底层框架并行流在底层沿用的框架,递归式的分解问题,然后每段并行执行,最终由合并结果,返回最后的值。 本书第六章的读书笔记,也是我这个系列的最后一篇读书笔记。后面7、8、9章分别讲的测试、调试与重构、设计和架构的原则以及使用Lambda表达式编写并发程序,因为笔记不好整理,就不写了,感兴趣的同学自己买书来看吧。 并行化流操作 关于并行与并发...

    leone 评论0 收藏0
  • java 8 实战》读书笔记 -第四章 引入

    摘要:第四章引入流一什么是流流是的新成员,它允许你以声明性方式处理数据集合通过查询语句来表达,而不是临时编写一个实现。 第四章 引入流 一、什么是流 流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码。 下面两段代码都是用来返回低...

    jeyhan 评论0 收藏0
  • Java8实战》-第六章读书笔记(用收集数据-01)

    摘要:收集器用作高级归约刚刚的结论又引出了优秀的函数式设计的另一个好处更易复合和重用。更具体地说,对流调用方法将对流中的元素触发一个归约操作由来参数化。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。 用流收集数据 我们在前一章中学到,流可以用类似于数据库的操作帮助你处理集合。你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作(如 filt...

    EscapedDog 评论0 收藏0
  • java 8 实战》读书笔记 -第十四章 函数编程的技巧

    摘要:但是,最好使用差异化的类型定义,函数签名如下其实二者说的是同一件事。后者的返回值和初始函数的返回值相同,即。破坏式更新和函数式更新的比较三的延迟计算的设计者们在将引入时采取了比较特殊的方式。四匹配模式语言中暂时并未提供这一特性,略。 一、无处不在的函数 一等函数:能够像普通变量一样使用的函数称为一等函数(first-class function)通过::操作符,你可以创建一个方法引用,...

    nemo 评论0 收藏0
  • Java 8 函数编程读书笔记——lambda表达

    摘要:本文是函数式编程第二章的读书笔记。的语法简化了使用匿名内部类时的模板代码,让程序员专注于编写想要执行的行为,也让代码更加简洁易读。中最重要的函数接口类型推断为新成员表达式提供了类型推断的支持,在不需要声明参数类型的表达式中表现的有为明显。 本文是「Java 8 函数式编程」第二章的读书笔记。 Lambda引入的变化 Lambda表达式,是一种紧凑的、传递行为的方式,从编程思想上来讲,...

    lx1036 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<