摘要:一提到编程范式,很容易联想到宗教的虔诚,每种宗教所表达信条都有必定合理性,但若是一直只遵循一种教条,可能也被让本身痛苦不堪,编程范式也是如此。
案例一,代码摘抄来自一企业培训材料,主要代码逻辑是打印每课成绩,并找出学生非F级别课程统计平均分数:算法
class CourseGrade { public String title; public char grade; } public class ReportCard { public String studentName; public ArrayList<CourseGrade> cliens; public void printReport() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); Iterator<CourseGrade> grades = cliens.iterator(); CourseGrade grade; double avg = 0.0d; while (grades.hasNext()) { grade = grades.next(); System.out.println(grade.title + " " + grade.grade); if (!(grade.grade == 'F')) { avg = avg + grade.grade - 64; } } avg = avg / cliens.size(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + avg); } }
上面的代码有哪些问题呢:编程
培训材料并未给标准解题,尝试优化一下代码,采用Java8的Stream来简化计算过程,并对代码进行了分段:segmentfault
public void printReport2() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); }
进一步优化,把各种打印抽取各自函数:设计模式
private void printHeader() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); } private void printGrade() { System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); } private void printAverage() { double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); } public void printReport3() { printHeader(); printGrade(); printAverage(); }
注:若是只算非F的平均分,能够一行搞定:闭包
double avg = cliens.stream().filter(it -> it.grade != 'F').mapToDouble(it -> it.grade - 64).average().orElse(0.0d);
List<Integer> tanscationsIds = transcations.parallelStream() .filter(it -> it.getType() == Transcation.GROCERY) .sorted(comparing(Transcation::getValue).resersed()) .map(Transcation::getId) .collect(Collectors::toList());
代码很是清晰:编程语言
这看起来是否是像这样一条SQL语句:select t.id from tanscations t where t.type == 'GROCERY' order by t.value desc函数式编程
目前Java8已普遍使用,对于Stream与Lambda应习觉得常了,而再也不是一种炫技。网上也有很是多的教程,如有同窗还不熟悉他们的用法,能够多找找材料熟悉一下。函数
Stream正如其名,像一条数据生产流水线,逐步叠加中间操做(算法和计算),把数据源转换为另外一个数据集。工具
笔者很早之前学过C#,接触过LINQ(Language Integrated Query),它比Java的Stream和Lambda用法更为清晰简洁,先给个简单示例:学习
var result = db.ProScheme.OrderByDescending(p => p.rpId).Where(p => p.rpId > 10).ToList();
LINQ为数据查询而生,能够算是DSL(Domain Specific Language)了,背后也是函数式编程(FP)一套理念,先记住其中两点:
FP还有其它的特性:模式匹配,柯里化,偏函数,闭包,尾递归等。对FP感受兴趣的同窗不妨找找材料学习一下。
如今的主流语言,都引入一些FP特性来提高语言在数据上的表达能力。
C++11引入Lambda表达式,并提供<algorithm>,<functional>两个基础库,一个简单示例:
int foo[] = { 10, 20, 5, 15, 25 }; std::sort(foo, foo+5, [](int a,int b){return a > b;});
Python提供functools库来简化一些函数式编程(仍是至关的弱),一个简单示例:
foo = ["A", "a", "b", "B"] sorted(foo, key=functools.cmp_to_key(locale.strcoll))
固然,面向对象语言中增长lambda这类特征不能就称为函数式编程了,大部分只不过是语法糖。是采用什么编程范式不在于语言的语法,而是在于思惟方式。
面向对象编程(OOP)在过去20多年很是成功,而函数式编程(FP)也不断地发展,他们相生相息,各自解决不一样的场景问题:
现实业务需求每每体现为业务活动,它是面向过程的,即先输入数据源,在必定条件下,进行一系列的交互,再输出结果。那面向过程与函数式的的区别是什么:
面向对象的编程经过封装可变的部分来构造可以让人读懂的代码,函数式编程则是经过最大程度地减小可变的部分来构造出可以让人读懂的代码。
咱们从Java的Stream实现也看到函数式的另外一个特色:
结合上面的理解,咱们能够先把世界事物经过OOP抽象为对象,再把事物间的联系与交互经过FP抽象为执行单元,这种结合或许是对业务活动的实现一种较好的解决方式。
一提到编程范式,很容易联想到宗教的虔诚,每种宗教所表达信条都有必定合理性,但若是一直只遵循一种教条,可能也被让本身痛苦不堪。编程范式也是如此,正如Java在1.8以前是纯面向对象式,你就会以为它很是繁琐。也如Erlang是纯函数式,你就会发现有时简单的逻辑处理会很是复杂。
近些年来,因为数据分析、科学计算和并行计算的兴起,让人认识到函数式编程解决数据领域的魅力,它也愈来愈受欢迎。在这些领域,程序每每比较容易用数据表达式来表达,采用函数式能够用不多代码来实现。
现实的业务软件,不少的逻辑其实也是对数据的处理,最简单是对数据的CURD,以及数据的组合、过滤与查询。因此函数式编程在许多语言中都获得支持,提高了对数据处理的表达能力。
了解新的编程范式在适当的时候使用它们,这会使你事半功倍。不管什么编程范式,他们都是工具,在你的工具箱中,可能有锤子,螺丝刀…,这个工具在何时使用,取决待解决的问题。
本文的案例只是一个引子,主要是想给你带来函数式编程的一些理念,函数式给咱们解决业务问题提供了另外一种思惟方式:如何高效简洁地对数据查询与变换。许多语言都支持函数式一些能力,须要咱们不断地学习,在合理的场景下使用他们。
本文分享自华为云社区《飞哥讲代码16:函数式让数据处理更简洁》,原文做者:华为云专家。