函数式编程的原理和优点

JAVA herman 1407浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

我在 WebFlux 教程中已经阐明了一种观点,函数式编程(Functional programming)将成为未来编程的一种趋势。我们也可以从 Java 8 等新版本中看到这种趋势。所以关于函数式编程的原理,优缺点?什么是函数式编程?等问题,我做一个总结,希望能够方便到大家的学习和理解!

函数式编程

什么是函数式编程?

函数式编程的第一个特点就是可以把函数作为参数传递给另一个函数,也就是所谓的高阶函数。例如,对数组进行排序,可以传入一个排序函数作为参数:

String[] array = { "xttblog", "yyucao", "www.xttblog.com" };
Arrays.sort(array, String::compareToIgnoreCase);

函数式编程的第二个特点就是可以返回一个函数,这样就可以实现闭包或者惰性计算。

函数式编程

函数式编程的好处

那么根据简化了的函数式编程的特点,函数式编程有什么好处呢?

从代码的可维护性上讲,函数式编程最大的好处是引用透明,即函数运行的结果只依赖于输入的参数,而不依赖于外部状态,因此,我们常常说函数式编程没有副作用。

没有副作用有个巨大的好处,就是函数内部无状态,即输入确定,输出就是确定的,容易测试和维护。

下面我们通过一个例子来看它的好处!

比如一个财务软件,需要一个函数专门计算个人所得税,输入是一个 IncomeRecord,输出是个税金额:

double calculateIncomeTax(IncomeRecord record) {
    // 省略具体实现
}

然后假设 IncomeRecord 长这样:

class IncomeRecord {
    String carId; // 身份证号
    String name; // 姓名
    double salary; // 工资
    String address;// 地区
}

然后,我们不考虑其它的社保、公积金等乱七八糟的东西内容。我们只简化为,扣减一个免征额后多月的按 20% 的税收计算。

double threshold = 3500; // 免征额
double calculateIncomeTax(IncomeRecord record) {
    if(record.salary <= threshold){
    	return 0;
    }else{
    	return (record.salary - threshold) * 0.2;
    }
}

上面这个程序在 2018 年 10 月 1 号前是没问题的,问题是 2018 年 10 月 1 号后起征点调整到了 5000,那 2018 年 9 月和 2018 年 10 月,计算结果应该不一样。上面的税收方式就需要调整?怎么调整呢?

double threshold = today() < date(2018, 10, 1) ? 3500 : 5000; // 免征额
double calculateIncomeTax(IncomeRecord record) {
    if(record.salary <= threshold){
    	return 0;
    }else{
    	return (record.salary - threshold) * 0.2;
    }
}

这样改代码,看起来没错,但是在实际运行中,可能会出问题。

比如,我们 10 月份,实际上发的是 9 月份的工资吧。这个系统,在 9 月 30 号跑,和 10 月 1 号跑,结果不一样。比如,我们在 10 月 2 号这天发工资。但是这次发工资我们是按照上月的考勤来统计个税的,然后会计要在 10 月 1 号做 9 月份的工资条,和 9 月 30 号做工资条,结果并不一致。难道要求会计必须把电脑的时间先调到 9 月份?

所以,这个问题,我们用函数式编程思维就很好解决了。calculateIncomeTax() 不再是一个纯函数,它与当前时间相关了。现在我们把它变成一个纯函数。

class IncomeRecord {
    String id; // 身份证号
    String name; // 姓名
    double salary; // 工资
    String address;// 地区
    int year; // 年
    int month; // 月
}

calculateIncomeTax 函数也在调整一下:

double calculateIncomeTax(IncomeRecord record) {
    double threshold = date(record.year, record.month) < date(2018, 10) ? 3500 : 5000;
    if(record.salary <= threshold){
        return 0;
    }else{
        return (record.salary - threshold) * 0.2;
    }
}

虽然这个问题,不用函数式编程也能解决。但是拥有函数式编程思维比解决问题本身更重要。

总的来说,函数式编程强调将计算过程分解成可复用的函数,典型例子就是 map 方法和 reduce 方法组合而成 MapReduce 算法。更多函数式编程知识,请参考我的 WebFlux 教程

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 函数式编程的原理和优点