软件设计之美
郑晔
开源项目 Moco 作者
19890 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
软件设计之美
15
15
1.0x
00:00/00:00
登录|注册

加餐 | 函数式编程拾遗

你好,我是郑晔!
我们之前用了三讲的篇幅讲了函数式编程,相信函数式编程在你心目中已经没有那么神秘了。我一直很偏执地认为,想要成为一个优秀的程序员,函数式编程是一定要学习的,它简直是一个待人发掘的宝库,因为里面的好东西太多了。
不过,考虑到整个课程的主线,我主要选择了函数式编程在设计上有较大影响的组合性和不变性来讲。但其实,函数式编程中有一些内容,虽然不一定是在设计上影响那么大,但作为一种编程技巧,也是非常值得我们去了解的。
所以,我准备了这次加餐,从函数式编程再找出一些内容来,让你来了解一下。相信我,即便你用的不是函数式编程语言,这些内容对你也是很有帮助的。
好,我们出发!

惰性求值

还记得我们第 17 讲的那个学生的例子吗?我们继续使用学生这个类。这次简化一点,我只使用其中的几个字段:
class Student {
// 学生姓名
private String name;
// 年龄
private long age;
// 性别
private Gender gender;
public Student(final String name,
final long age,
final Gender gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
然后,我们来看一段代码,你先猜猜这段代码的执行结果会是什么样子:
// 数据准备
Student jack = new Student("Jack", 18, Gender.MALE);
Student rose = new Student("Rose", 18, Gender.FEMALE);
List<Person> students = asList(jack, rose);
// 模拟对象
Function<Person, String> function = mock(Function.class);
when(function.apply(jack)).thenReturn("Jack");
// 映射
students.stream().map(function);
// 验证
verify(function).apply(jack);
这段代码里,我们用到了一个 mock 框架 mockito,核心就是验证这里的 function 变量是否得到了正确的调用,这其中就用到了我们在第 18 讲中提到的 map 函数。
也许你已经猜到了,虽然按照普通的 Java 代码执行逻辑,verify 的结果一定是 function 得到了正常的调用,但实际上,这里的 function 并没有调用。也就是说,虽然看上去 map 函数执行了,但并没有调用到 function 的 apply 方法。你可以试着执行这段代码去验证一下。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

函数式编程中的惰性求值、无限流和记忆是本文介绍的技术特点。惰性求值通过延迟求值过程,避免不必要的计算;无限流利用惰性求值创造出无限长集合,适用于大数据平台等场景;记忆则是一种优化技术,将昂贵函数的结果存储起来,以便再次调用时返回缓存的结果。文章还提供了一个实现记忆技术的例子,展示了函数式编程中的实际应用。这些技术特点展示了函数式编程的灵活性和实用性,对于程序员来说具有很高的学习和应用价值。此外,文章还介绍了函数式编程中的Optional概念,它是一个对象容器,用于解决空对象问题。通过对Optional的使用,可以减少空指针异常的发生,并且给方法的使用者一个提示,表明返回的对象可能为空,需要小心处理。文章还提到了Optional与函数式编程中的Monad概念的关系,以及在Rust标准库中的应用。总的来说,本文通过介绍惰性求值、无限流、记忆和Optional等概念,展示了函数式编程的优秀之处,鼓励读者花时间学习函数式编程。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《软件设计之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • qinsi
    * 记忆化是Memoization,正文里应该是拼错了,示例代码里是对的; * 个人理解单凭记忆化还无法取代Proxy模式,因为Proxy模式主要是做方法调用的分发(dispatch),在分发时可以做些额外的事情(比如记忆化)。单是实现动态分发的话Java里可以用反射,Ruby里可以用method_missing等,并不是一种很稀缺的语言特性; * Option的价值在于类型而非对象。是类型的话在编译时编译器就可以进行检查,而不是依赖程序员在运行时进行检查(或是依赖IDE)。能处理Option的函数也是这个思路,程序员在进行中间处理时可以不用自己处理empty值,只需要确保类型正确; * Monad是个被诅咒的名字,日常开发中不应该提到它 ;-)

    作者回复: 多谢提醒纠错! 非常好的补充,你的补充提升了这篇文章的整体价值。 你对 Monad 的观点,我非常同意!

    2020-07-10
    5
    25
  • 奔奔奔跑
    老师您好,有幸阅读本专栏,让我见识到了优秀的程序对代码认知应该是怎么样的!但是得到了老师的内功心法,感觉有劲使不出来,总差一层窗户纸。不知道为啥,希望老师能够指点!谢谢

    作者回复: 知和行的差异,首先,你要知道有哪些知识,其次,是知道怎么在开发中运用这些知识。 在这个专栏里,我帮助大家解决的是知的问题,因为很多人不知道有哪些软件设计的知识。至于行,就需要在每天的日常开发中,多问问自己这段代码写得是否破坏了某个设计原则。 软件设计是日常的功夫,需要在每次写代码的时候,都去问问自己。只有通过不断地练习,让这些知识内化为自己的一部分,才算是真正学会了。 当然,如果有人能够近身指导会好一些,这需要通过训练营的形式进行训练,目前,这种训练营我只做过一些企业内训,还没有成为大规模的。

    2020-07-19
    3
    11
  • naijiz
    老师,我有个不懂的地方,在使用Optional的时候,该空的还是会空,该判断的还是要判断,这个容器是只解决嵌套if的问题吗?

    作者回复: 你要使用实际的对象时,你必须考虑取出来的问题,就会考虑判断的问题,不像直接使用对象,缺少了一步思考,就容易犯错误。所以,重点在于,减少犯错误的可能性。

    2020-07-24
    6
  • Fredo
    最近看黑客与画家这本书,里面一节谈编程语言Lisp,是朝着数学的方法发展。作者说 编程语言现在的发展不过刚刚赶上1958年的Lisp语言的水平,很吃惊 翻了下,书是04年出版的。那现在的编程语言跟Lisp语言比何如呢?

    作者回复: Paul Graham 是个优秀的程序员,他对 Lisp 是有偏爱的,而且 Lisp 能够提供的抽象能力很强,它也成为了很多高手的挚爱。抽象这种东西要求很高的,大多数人的水平达不到,我们这个专栏讲的其实就是如何构建抽象。Lisp 也正是因为太强大了,很多人不能很好的理解,所以,它的流行度也很低。Lisp 是一个很好的思维训练工具,但不是大部分人的营生。

    2021-11-06
    5
  • 很庆幸能订阅这个专栏,希望老师能出第二部软件设计方面的课程,我觉得您的课程才是大宝藏

    作者回复: 想更多了解什么,尽管说。

    2020-07-13
    2
    4
  • 孜孜
    有些语言的如JS C#的(?.)和optional是不是异曲同工?

    作者回复: 是

    2020-07-18
    2
  • giteebravo
    雾里看花,水中望月~

    作者回复: 至少知道了那里有花有月。

    2020-07-17
    2
    2
  • 阳仔
    函数式编程是应当好好普及,这是一个编程思想的转变

    作者回复: 语言上已经开始普及,思想上路还长。

    2020-07-10
    2
  • 被雨水过滤的空气
    函数式比较难的是怎么样对外界施加作用,又能保证写的是纯函数。

    作者回复: 在实际工作中,努力把外部的部分隔离开来。让自己的代码纯起来。

    2020-07-10
    2
    2
  • 6点无痛早起学习的和尚
    然后抓虫:然后,我们来看一段代码,你先猜猜这段代码的执行结果会是什么样子 下面这个代码 Person 应该是 Student
    2023-09-21归属地:北京
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部