`

Java函数式编程学习笔记(一)

阅读更多

1. 此函数非彼函数

在弄清楚什么是函数编程之前,有必要先弄清楚究竟什么是函数这个问题。在面向对象编程中,我们经常将方法称为函数,那么方法与函数究竟是否是同一个东西的不同称呼呢?函数式编程中的“函数”是指数学意义上的函数,不是编程语言中的“函数”。数学上的函数(Function)可以看成一个小机器,给这个机器提供一定的原材料(输入参数),它就会加工出(输出)一定的产品(返回值),如图1所示。

图1 函数示意图

图片来自:https://en.wikipedia.org/wiki/Function_(mathematics)

方法往往是有副作用(Side Effect)的,即一个方法的调用往往意味着对象状态的变化,而这种变化可能使得用同样的参数多次调用同一个方法,每次调用的返回值可能各不相同。而数学上的函数是没有副作用的(Side Effect Free),因此只要使用同样的参数调用同一个函数,那么不管调用这个函数多少次,每次调用的返回值总是相同的。例如,对于一个计算矩形面积的函数f(x,y)=x*y(x和y代表矩形的长和宽),那么无论调用多少次f(3,4),每次的返回值总是12。

从“无副作用”的角度来看,一个方法只要对其的调用不会产生副作用,那么它就是一个函数,否则它就不是函数。例如,String.charAt(int)这个方法就是一个函数。System.currentTimeMillis()这个方法就不是函数,因为对其的每次调用的返回值都可能不相同。

2. 函数式编程:函数作为“一等公民”

面向对象编程是Java平台在Java 8之前就已经支持的一种编程范式(Paradigm),Java平台从Java 8开始支持另外一种编程范式——函数式编程(Functional Programming)。面向对象编程中,对象是“一等公民”。所谓“一等公民”就是指可以作为“值”的语言元素。“值”既可以赋值给变量,也可以作为方法调用的参数进行传递以及作为方法的返回值。例如,我们可以将“1024”赋值给一个int型变量,也可以将其作为方法调用的参数,或者作为一个方法的返回值。同样,对象(确切的说是对对象的引用,相当于指针)也可以作为一个变量(引用型变量)值或者作为一个方法调用的参数,或者作为一个方法的返回值(返回一个对象的方法我们通常称之为工厂方法)。

在面向对象编程中,方法(或者函数)并非“一等公民”,因为方法在这里就不是一个值。而在函数式编程中,函数翻身成为“一等公民”,因此在这里函数可以作为一个值赋值给一个变量,可以作为函数调用的参数(即用函数作为参数去调用一个函数),可以作为函数的返回值(即一个函数的返回值是另外一个函数)。

3. 函数式编程的优势

3.1. 编写更为简洁的代码

函数式编程使得我们能够编写更为简洁的代码。下面看一个例子。假设有个服务(如清单1所示),其启动动作(即Service.start()方法)比较耗时,因此我们希望用异步的方式去启动这个服务,以避免主线程被阻塞。

清单1 一个启动比较耗时的服务

public class SomeTimeConsumingService implements Service {
 @Override
 public void start() {
  // 模拟启动动作的耗时
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   ;
  }
 }
}

为此,我们只需要创建一个专门的线程(工作者线程),并在该线程的run方法中调用Service.start()即可,如清单2所示。

清单2 以异步方式启动一个耗时服务(面向对象编程)

public class ServiceStarter {
 public static void main(String[] args) {
  Thread serviceStarter;
  final SomeTimeConsumingService service = new SomeTimeConsumingService();
    //创建Runnable实例以调用Service.start()
  serviceStarter = new Thread(new Runnable() {
    @Override
    public void run() {
       service.start();
     }
   });
          //启动线程
  serviceStarter.start();
 }
}

清单2中我们创建的匿名Runnable实例的目的仅仅是为了在工作者线程中调用Service.start()而已。如果我们能够直接把Service.start()方法作为一个参数传递给Thread类的构造器(姑且将构造器看做一种特殊的方法),那么这里我们也就省却了创建Runnable实例,从而使代码更加简洁。在Java 8之后我们的确可以这么做,如清单3所示。

清单3 以异步方式启动一个耗时服务(函数式编程)

public class ServiceStarterFP {
 public static void main(String[] args) {
  Thread serviceStarter;
  final SomeTimeConsumingService service = new SomeTimeConsumingService();
  serviceStarter = new Thread(service::start);//直接将start方法作为参数传递给构造器
  serviceStarter.start();
 }
}

这里,“service::start”是一个方法引用(Method Reference),它表示对象service的start方法。可见,我们将一个方法作为一个参数传递给了Thread类的构造器,这使得清单3相比清单2中相应代码要简洁一些。读者也许在想,Thread类的构造器的参数的类型是java.lang.Runnable,何以我们能够将一个方法(作为“值”)作为其参数传入呢?这样为何不会出现类型不匹配(兼容)的问题呢?后续的笔记中我们会解释这一点。

从这个例子我们可以看到,Java 8中方法已然跻身作为函数的“一等公民”行列,因此方法可以作为参数进行传递。显然Service.start()并不是真正意义上函数,因为它是有副作用的(至少它有可能是有副作用的,因为它是用来启动一个服务的)。尽管如此,这个方法还是享受到了函数的“一等公民”待遇(作为值传递)。由此可见,Java 8中一个方法可以看做是一个函数,但是Java并不强制这个方法必须是无副作用的。

3.2. 函数式编程为并发编程提供了便利

函数式编程为并发编程提供了便利。函数是无副作用的,这就意味着这函数必须是无状态(Stateless)。无状态是多线程编程和函数式编程的共同好友。我们知道,在多线程编程中,如果多个线程之间存在共享可变状态(Shared Mutable State),那么为了确保线程安全我们往往需要借助锁,而锁除了其开销较大之外还存在可能导致死锁等问题。相反,如果多个线程之间不存在共享状态(或者仅存在只读状态),那么这些线程是可以并行(Parallel)的。这不仅有利于提高系统的并发性,也使得代码更为简单。函数也是类似,既然函数是(必须是)无状态的,那么多个线程同时执行一个函数的时候也就无需加锁,这既简化了代码又有利于提供系统的并发性。

4. 作者简介

黄文海,著有《Java多线程编程实战指南(核心篇)》《Java多线程编程实战指南(设计模式篇)》

5. 参考资料

1.Raoul-Gabriel Urma等.Java 8实战.人民邮电出版社,2016

2.黄文海.Java多线程编程实战指南(核心篇).电子工业出版社,2017

3.黄文海.Java多线程编程实战指南(设计模式篇).电子工业出版社,2015

0
0
分享到:
评论

相关推荐

    Java 8函数式编程学习笔记.zip

    Java 8函数式编程学习笔记

    java8集合源码分析-LearnJava8:《Java8实战》学习笔记

    函数式数据处理 第三部分 高效Java 8编程 第四部分 超越Java 8 第一部分 基础知识 1 2 3 第二部分 函数式数据处理 4 5 6 7 第三部分 高效Java 8编程 8 9 10 11 12 第四部分 超越Java 8 13 14 15 16 附录

    scala.rar学习笔记和心得

    Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。 Scala 源代码被编译成Java字节码,所以它可以运行于...

    scala学习资料

    Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。

    高级java笔试题-reading-notes:做阅读笔记和练习

    同上述的Java8函数式编程一起看的,相比上面的书,这本书难度偏低,内容都是JavaSe8的新特性,适合快速熟悉JavaSe8。 JavaWeb Sprint Boot2 精髓 从构建小系统到架构分布式大系统() 缺点:书名有点夸张,作者喜欢...

    Matlab学习笔记.rar

    行矩阵运算、绘制函数和数据、实现算法、创建用户界面、连接其他编程语言的程序等。MATLAB的基本数据单位是矩阵,它的指令表达式与数学、工程中常用的形式十分相似,故用MATLAB来解算问题要比用C,FORTRAN等语言完成...

    韩顺平oracle学习笔记

    韩顺平oracle学习笔记 第0讲:如何学习oracle 一、如何学习oracle Oracle目前最流行的数据库之一,功能强大,性能卓越。学习oracle需要具备一定基础: 1.学习过一门编程语言(如:java ,c) 2.最好学习过一门别的...

    JAVA学习笔记2020/4/27——Stream流、方法引用

    在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。 1.1 引言 传统集合的多步遍历代码几乎所有的集合(如Collection接口或Map接口等)都支持直接或间接的...

    最新IT书籍G3期

    《Java 8函数式编程》_王群锋译_2015-04-01 《Java JDK 9学习笔记》_林信良_2018-06-01 《Neo4j 3.x入门经典》_张帜等_2019-02-01 《分布式系统常用技术及案例分析(第2版)》_柳伟卫_2018-12-01

    learnrx:学习者布多乔

    事实证明,学习Rx的关键是训练自己使用函数式编程来操纵集合。 函数式编程为开发人员提供了将常见集合操作抽象为可重用,可组合的构建块的工具。 您会惊讶地发现,您对集合执行的大多数操作都可以通过五个简单的...

    java8集合源码分析-javaLearner:java学习者

    《深入理解Java虚拟机》、《并发编程的艺术》、《Java多线程核心编程艺术》、《Java8函数式编程》、《Redis设计与实现》、《RocketMQ技术内幕》、《Spring技术内幕》、《Spring源码深度解析》、《剑指Offer》、...

    中国移动重庆java笔试题--:前端学习知识

    中国移动重庆java笔试题 说明 平时的学习资源都比较的凌乱...函数式编程 Underscore Typescript webpack 源码 Parcel Gulp es系列 Babel HTTP http 请求库 Promise NodeJS MongoDB Git canvas 移动端 技术类 微信小程序

    程序员考试刷题-java8-ocp-study-notes:跟踪OCPJava8书籍学习指南的存储库

    程序员考试刷题java8-ocp-study-notes 跟踪 OCP Java 8 书籍学习指南的存储库 ...函数式编程 第 5 章 - 日期、字符串和本地化 第 6 章 - 异常和断言 第 7 章 - 并发 第 8 章 - IO 第 9 章 - NIO.2 第 10 章 - JDBC

    java安卓仿微信聊天软件源码-Front-end-stack:需要学习的前端知识

    JS函数式编程指南 JavaScript Promise迷你书(中文版) 腾讯移动Web前端知识库 Front-End-Develop-Guide 前端开发指南 前端开发笔记本 大前端工具集 - 聂微东 前端开发者手册 入门类 地址 前端入门教程 瘳雪峰的...

    java安卓仿微信聊天软件源码-lerningCenter:学习中心

    JS函数式编程指南 JavaScript Promise迷你书(中文版) 腾讯移动Web前端知识库 Front-End-Develop-Guide 前端开发指南 前端开发笔记本 大前端工具集 - 聂微东 前端开发者手册 入门类 入门类 地址 前端入门教程 瘳...

    高级java笔试题-Notes-And-Blog:阅读笔记及高质量博客整理

    函数式编程 :butterfly:Nodejs Nest :lady_beetle:TypeScript :lizard:Vue :dolphin:React react :mobile_phone:跨端应用 React-Native Flutter :rocket:Webpack :automobile: Gulp :construction:规范化 :tractor:...

    关于Scala那些事儿

    Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala 运行在Java虚拟机上,并兼容现有的Java程序。java、Scala都是基于JVM的编程语言(文件编译成class...

    亚信java笔试题-js-designer:大前端学习资料汇总,激励自己一下

    JS函数式编程指南 JavaScript Promise迷你书(中文版) 腾讯移动Web前端知识库 Front-End-Develop-Guide 前端开发指南 前端开发笔记本 大前端工具集 - 聂微东 前端开发者手册 入门类 入门类 地址 前端入门教程 瘳...

    front-end-eigineer-documents:前端工程师知识体系、前端学习笔记、前端工程师进阶路线、前端知识框架、前端面试问题

    前端知识体系(zh-ch) Github文档库更新慢,最新内容请关注语雀: ...函数式编程 [设计模式]:MVC/MVVM/MVP 前端开发工具 构建工具 webpack grunt gulp npm yarn 测试工具 Puppeteer Jest mocha 调试

Global site tag (gtag.js) - Google Analytics