原标题:面试被虐题:说说 JVM 系语言的函数式编程

Java中的函数式编程

函数式编程在上世纪五十年代就有了,只不过在工业界一直不温不火,最近十年才被广泛认知。其理论基础也并非为编程而设计,而是一种数学抽象(Lamda演算),其实初中就学过了,λ表达式。

在 JS(建议把 JS 作为函数式编程思想学习的入门语言,Java 的实现略显臃肿,可能不太便于理解)当中,函数式编程算是应用比较多的了。各现代高级编程语言,都或多或少地支持了函数式编程。

一些基本特点总结:

相比平常的指令式编程,函数式编程更在乎执行结果而非过程;

函数是一等公民,可以像普通的数值、引用等变量一样赋值、作为参数传递、作为返回值;

函数是纯函数,即函数不能产生副作用,如不能修改全局变量等,固定的输入就映射固定的输出。

简单示意一下,不代表任何语言,因为不同语言在实现方式上有差异,但核心思想不变:

1//定义一个函数g,并赋值给f

2f=g(x,y)=x+y

3//写一个方法,函数作为参数传递

4printF(g){

5print(g(1,2))

6}

7//调用方法

8printF(f)//打印结果3

9//作为返回值

10getF(){

11returnf

12}

Java 函数式编程

看了上面的示意,是不是能联想到 Java 的 Runnable 了?

1Runnablef=()->{

2//dosomething

3}

4voidtestF(Runnabler,inti){

5print(i);

6r.run();

7}

8testF(f,1);

9//看这个是不是有点函数式编程的影子了,其实Runnable接口的设计在Java8之前就有了,还是很有远见的,在此可以把f看成一个无参无返回值的函数,也算是低配版的函数式编程嘛~

所以我们在 Java 8 的编程环境下,经常看到 IDE 提示 new Runnable…… 可以转化成 lamda 表达式。

真正的函数式编程本来 Java 7 就会支持的,但是甲骨文跳票你懂的,于是 functional programming 在 Java 8 才正式推出。从 java.util.function 包即可管中窥豹。

Java 后端开发中早就用烂了,在 Android 开发中必须 API 大于等于 24 才能完全开启 Java 8 特性(最新:Studio 4.0 推出的新版 Gradle 插件已经支持解糖,不再需要 API 限制)。

Groovy 函数式编程

Gradle 脚本是基于 Groovy 这门 JVM 动态语言的,用它来表示函数式编程的概念更加清晰:

1deffunc1={msg1->

2println"Lookfunc1$msg1"

3

4deffun2={msg2->

5printlnmsg2

6"retfun2"//在闭包中最后一行值将直接作为返回结果,加不加return都可

7}

8returnfun2

9//等效简化代码

10//return{msg2->

11//printlnmsg2

12//"retfun2"

13//}

14}

15

16printlnfunc1('真的')('NB')

17

柯里化理论基础

柯里化是函数式编程的重要特性,简单理解就是把多参函数转化为一个个单一参数的元函数,第一个元函数处理完一个参数后,返回新一个元函数来处理剩下的参数,依此递归,就像工厂的流水线一样工作,各司其职。

我们平时用到的 builder、链式调用,其实都有这种概念在里面。

Java8 柯里化示例:

1importjava.util.function.Function;

2importjava.util.function.IntFunction;

3importjava.util.function.IntUnaryOperator;

4

5publicclassCurry{

6privatestaticfinalFunction>>CURRYING_1=

7x->y->z->(x+y)*z;

8privatestaticfinalIntFunction>CURRYING_2=

9x->y->z->(x+y)*z;

10privatestaticfinalTriFunctionCURRYING_3=

11(x,y,z)->(x+y)*z;

12

13publicstaticvoidmain(String[]args){

14System.out.println(CURRYING_1.apply(1).apply(2).apply(3));

15System.out.println(CURRYING_2.apply(1).apply(2).applyAsInt(3));

16System.out.println(CURRYING_3.apply(1,2,3));

17}

18

19@FunctionalInterface

20publicinterfaceTriFunction{

21Rapply(Uu,Tt,Ss);

22}

23}

低版本 Java 兼容实践

由于目前大多 Android 项目的 minSDK 对应的 API 等级还是 19 或者 23,且未升级至 Studio 4.0,并不能直接使用 Java 8 的全部特性,因此只能在编码层面进行部分特性的兼容:

1//build.gradle

2android{

3compileOptions{

4sourceCompatibilityJavaVersion.VERSION_1_8

5targetCompatibilityJavaVersion.VERSION_1_8

6}

7}

不过,我们也可以自己复制 java.util.function 包中的代码来实现函数式编程(比如 AndroidX 的工具包中就单独实现了 Consumer 接口),具体可参考 androidx.core.util.Consumer 的相关引用。

对函数式编程支持程度高低的一个重要特征是函数是否作为编程语言的一等公民出现,也就是编程语言是否有内置的结构来表示函数。作为面向对象的编程语言,Java 中使用接口来表示函数。

1//比如Consumer就是一种只接受一个输入,而没有输出的特殊函数

2publicinterfaceConsumer{

3voidaccept(Tt);

4}

5

6//为通知构建,创建一个PendingIntent

7publicstaticPendingIntentcreateActivityI(inttype,Consumerconsumer){

8ContextappCtx=MyApp.getContext();//获取App全局Context

9Intentintent=newIntent();

10intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

11if(consumer!=null){

12consumer.accept(intent);

13}

14returnPendingIntent.getActivity(appCtx,type,intent,PendingIntent.FLAG_UPDATE_CURRENT);

15}

16//外部调用

17PendingIntentclickI=createActivityI(INTENT_TYPE_TEST,intent->{

18intent.setData(xxx);

19intent.putExtra(xxx);

20//...对intent对象各种操作,无需关心内部是如何初始化的(实例化),我们只是外部消费者(consumer)

21});

上面这段代码可能咋一看跟真正的函数式编程并没有什么卵关系,甚至一般的 builder 模式也能实现。

但我们应该把 intent -> { ... } 看成一个λ函数表达式,intent 是唯一参数且不可变,并且我们应当遵守纯函数的规范,即 { ... } 函数实现内部只对 intent 进行修饰等操作,不应该去做其他无关的事情(比如修改外部变量,甚至是调起其他功能模块等)。

在消费者 consumer.accept() 的瞬间,内外互不相知干了什么,天然地做到了业务逻辑隔离。

请勿滥用

越抽象和高级的东西,内部消耗越大,乃自然之理。虽然函数式编程有很多优点,如可读性好,函数无副作用,参数不可变(理论上适合并行操作,不用考虑死锁,实际上性能不够,是不是挺矛盾的?)等。

但相比指令式编程,大量使用函数式编程,会影响程序性能。不适合做IO密集型操作和一些高性能的UI操作。从Java函数式编程的实现来看,内部也涉及到比较多的函数递归嵌套,给栈区带来一定的压力。

合理使用:平时工作中可以利用函数式编程的理念来简化业务代码,如上文示例,还是蛮好的。返回搜狐,查看更多

责任编辑:

x的平方加y平加xy的java语言_面试被虐题:说说 JVM 系语言的函数式编程相关推荐

  1. x的平方加y平加xy的java语言_JAVA语言及网络编程-中国大学mooc-题库零氪

    第1章 认识Java语言 单元测验1 1.使用计算机处理数据,输入原始数据必须放在下列哪个步骤之后? A.申请内存空间 B.数据处理 C.输出处理结果 D.未包含在选项中 2.如果程序中出现单词&qu ...

  2. python程序运行结果始终为0_下列 Python 程序的运行结果是( )。 x=0 y=True print(xy and 'A''B')_学小易找答案...

    [单选题]下列 Python 程序的运行结果是( ). x=0 y=True print(x>y and 'A' [判断题]城市轨道交通是公共交通铁路化的产物,因此它保留有铁路交通的部分基因,比 ...

  3. 执行下列python程序输出结果是什么_下列Python程序的运行结果是 x=0 y=True print(xy and 'A''B')_学小易找答案...

    [单选题]1869年,艾耶父子广告公司在( )创建,成为第一家现代意义上的广告代理公司,也标志着广告产业的形成. [单选题]用360浏览器下载杀毒软件,默认安装目录是( ). [填空题]4 在罗盘仪测 ...

  4. antd 表格加y轴滚动时行与行间错位问题

    当表格左侧或右侧列使用fixed 时,加y轴滚动会出现与普通行不对齐. .ant-table-body-outer{margin-top:5px !important; // 根据实际调整matgin ...

  5. 三维GIS场景加载平纵横 公路设计与现状地形更协调

    平纵横设计的主要目的是选择合理的弯曲半径,避开障碍物,选择合理的坡度,选择合理的横断面形式,控制施工量和工程量.在公路工程设计中,平纵横是设计工作的关键与重点,设计时需要考虑平纵横与现状地形的关系及协 ...

  6. 求从1到10 (k的平方)的连加和

    编写程序,求从1到10 (k的平方)的连加和 public class QiuHe {public static void main(String[] args) {int sum=0,j=1;for ...

  7. python计算1的平方减2的平方加3的平方减4的平方怎么算_已知X的平方加4x减一等于零 求2x的四次方加八X的三次方减四X的平方减八X加一的值...

    已知X的平方加4x减一等于零 求2x的四次方加八X的三次方减四X的平方减八X加一的值以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来 ...

  8. python一个图画两条曲线_用python建立两个Y轴的XY曲线图方法

    想把python提取出来的 加载点反力和某个单元的应力画在同一个XY曲线图上,由于两者数量级差太远,故而需要建立有两个Y轴的XY曲线图. 效果为: 代码如下: #创建Quatype,作为标记,用于判断 ...

  9. python画xy轴_用python建立两个Y轴的XY曲线图方法

    想把python提取出来的 加载点反力和某个单元的应力画在同一个XY曲线图上,由于两者数量级差太远,故而需要建立有两个Y轴的XY曲线图. 效果为: 代码如下: #创建Quatype,作为标记,用于判断 ...

  10. 用python建立两个Y轴的XY曲线图

    想把python提取出来的 加载点反力和某个单元的应力画在同一个XY曲线图上,由于两者数量级差太远,故而需要建立有两个Y轴的XY曲线图. 效果为: 代码如下: #创建Quatype,作为标记,用于判断 ...

最新文章

  1. 人机交互时,你认为机器人是有意识的还是无意识的?
  2. python社区发现_这个 Python 项目厉害了!多个实战案例教你分析时空数据处理
  3. Linux 如何快速找到运行中的进程
  4. PHP开发之环境配置
  5. HTTP1.1与HTTP1.0的区别
  6. arm7 mysql 编译安装_uboot的readme导读(转)
  7. java 批量增删改_java使用JDBC连接mysql并且进行批量增删改操作
  8. 2020计算机原理组成1254,1254计算机科学与技术专业计算机组成原理A科目2020年09月国家开 放大学(中央广播电视大学)考试试题及答案.pdf...
  9. 领英“顶尖公司”榜单出炉:华为、字节跳动位居前二
  10. 硬盘分区表知识—详解硬盘MBR
  11. 用最新MySQL 8.0的源安装MySQL 5.7版本(CentOS 7环境下)
  12. 阿里首席架构师分享的Java工程师职业规划
  13. @value取不到值_Bamboo window上环境变量 HOMEDRIVE 及 HOMEPATH 获取不到的问题
  14. java linux 系统队列,linux下消息队列
  15. User-Agent的变迁——浏览器大战之前世今生
  16. 介绍一下小规模纳税人如何开具增值税专用发票的流程
  17. ps6人脸识别液化工具在哪_ps液化工具在哪?(Photoshop基础教程:液化工具)
  18. endnote导入bib
  19. 好不容易找到的一篇dva教程
  20. 天嵌E9开发板tftp烧录eMMC教程(Android)

热门文章

  1. Mysql索引之-cardinality
  2. python中按位运算符_Python中的按位运算符详解
  3. 力扣-1128 等价多米诺骨牌对的数量
  4. ES系列三、基本知识准备
  5. Spring框架学习之SpringAOP(二)
  6. 对课程第二次作业的补充与反馈
  7. PHPExcel如何把该列的值设置为文本无科学计数?
  8. ASP实现AJAX的几种方式!
  9. 静态路由实现路由过滤
  10. 使用Python来调用电脑音响