去年某个偶然的契机,初识Stream Api,瞬间被其紧凑简练的风格吸引了,接着便开始一头扎进所谓的函数式编程的深坑,然后了解了Optional 高阶函数 科里化等特性,后来又结合泛型等特性重新梳理了一遍java基础,让编码风格脱胎换骨,与纯面向对象的java7不同,对函数式越是了解便越能从中感受到一种难以言喻的爽快感,抽象但是不乱,仿佛以前不管多复杂的业务逻辑,在函数式编程的思想面前都是战斗力只有5的渣渣。瞬间被拆解成单层逻辑。既能运行高效,又能提高代码可维护性,同时可读性也飙升,这种好事哪里去找?然而还真有。
对于java程序员尤其是java7及其以下的程序员而言,有两件事恐怕是司空见惯的,其一就是复制粘贴代码,产生很多相似度很高的代码,其二就是对变量进行多次赋值,而且大家也都没感觉这样做有什么不妥,这也是过程式编程的最基本思路,人脑模拟电脑工作,可是绝大多数情况,让人痛苦的并不是写代码,更多的是改代码,这样就伴随着两种让人抓狂的事
一种是为了调整一个效果,要改动无数个地方,
一种是只改动一个地方,却影响了很多效果
前者的原因是由于代码冗余造成的,说白了就是复制粘贴代码造成的,如果仅仅是多复制粘贴几下倒也没什么,问题是一旦少改或错改一处便会产生很多难以预料的bug。后者便是我所说的“状态”,至少这个是过程式语言司空见惯的一件事,喜欢在程序中放很多变量,然后后面的代码根据前面变量的状态来进行相关的操作,这样用人来模拟计算机指令的行为倒也没有什么,但是在多人合作的项目总是什么样牛鬼蛇神的代码都有,比如有的喜欢动辄写一个几百上千行的方法,让解析的人看的时候要死死盯着每一个可能变化的值来解析,如果是局部变量倒也还不算过分,如果这个状态是全局变量呢?这个时候维护的人就要打起12分精神,还要全工程ctrl F 把所有的可能赋值的地方高亮来调查,如果说这样还是可以接受的话,那。。。如果还有多线程呢?还有锁呢?这个时候如果还有领导催活的话,恐怕维护这段的人杀人的冲动都有了吧,这都是我在实际项目中亲自维护过的东西,更加过分的是还有使用存储过程,存储过程调存储过程调存储过程。。。,让一个需求下来所用的工时根本无法预估,因为你根本就无法预知它究竟关联多少东西,多少状态,这个状态又有多少模块依赖,被依赖的模块又要改多少状态无限循环。
还有一个东西就是设计模式,其实原本设计模式是个十分伟大的发明,但是在纯面向对象的java面前,更像一块鸡肋,使得它的好处并不是那么明显,然后很多工作很多年的老油条会以一个长 者的的语气批判你一番,说你敲的代码还不够多,等你敲了几十万行代码就会感觉它的好处了,也有很多公司面试的时候喜欢拿设计模式来压人,先摆出23个设计模式,不会直接pass,可是啊,我不会自己骗自己,不好用的东西就是不好用,不要拿代码量那种东西压我,设计模式的初衷在于解决纯面向对象的语言的耦合度过高的一种比较临时方案,却被很多人奉为解决问题的银弹,更过分的是有很多人为了设计模式而设计模式,为了抽象而抽象,这就导致了一个什么样的结果呢?尤其是很多个人都想用设计模式的时候,一个原本很简单的一个操作,你调查的时候却要跳几十个类,跳来跳去,继承来继承去,导致代码像封建时代的裹脚布又臭又长,然后美其名曰扩展性,最后精心准备的设计模式就烂在这里。十年八年都没人用。
代码冗余,难以预知的状态变化,设计模式的滥用,时不时出现的bug,动不动就改的需求,无尽的加班,脱发 让很多java程序员痛苦不堪,还不到35就成天嚷嚷着要退休,然而这无底深坑其实还有自己的一砖一瓦。我也在很长的一段时间都在怀疑自己是否选错专业了,因为程序员在我的印象中一直是一种靠吃青春饭的职业,看着周围的人年纪轻轻就秃顶,那种压力我恐怕也坚持不到35岁,也许有人喜欢钻进复杂之中并乐在其中,然后拿着if else 循环已经嵌套到扭曲的代码,自豪的给新人讲解着好几百上千行,几十个类的复杂逻辑,然后从新人一脸懵逼的状态获取一丝短暂的满足感,但是我不是,我始终相信的一件事就是,一个问题要用最简单最直接的手段去解决,写代码又不是阅读理解题,天为什么下雨了,窗帘为什么是紫色的,我不想知道,我只知道两点之间线段最短,哪有那么多草木皆兵,能直接解决的问题不应该绕那么多弯子。
再说设计模式,刚才我仿佛一直再说设计模式多么不好,其实设计模式并不是那么糟糕的东西,它的糟糕之处主要在于它依赖于自定义的接口,由于java的函数是强绑定于类上的然后叫它方法,拿策略模式来说,就要每个策略要生成一个新的类,整个项目缺乏统一标准,污染了整个项目的代码环境,java7有匿名内部类,而匿名内部类可读性却奇差,这让它的优点和缺点相互抵消了,而lambda表达式和函数式接口却直接去除了这些副作用,直接凸显的就是其优点,尽管从本质而言并没有什么变化,但是两个工具哪怕只差一点点,我肯定会选更好用一点的那个,更何况,它们相差的岂止一点点,lambda表达式的意义有多大呢?你能想象java去掉判断循环等语句直接让你写goto的感觉吗?就差这么多,这个语法糖真的很甜,用Stream APi 和Optional可以让代码的缩进只有一层,只要合理运用,可以让这个代码下来不用写注释便能清晰的知道其具体在干什么,高阶函数配合泛型可以让相似逻辑得以最高效率的重用,让代码没有复制粘贴,没有不确定的状态,没有多线程锁,bug越来越少,如果说设计模式是把bug的可能封装起来,那函数式编程就是从一开始就将bug扼杀在摇篮里。
面向对象和函数式编程的对比文章网上一搜就有一堆,我说点个人的理解吧,面向对象由于函数是不能传递的,因而为了弥补这个缺陷,它会十分频繁的使用继承、接口回调、抽象类这些如果没有充分的理解就极易出错的特性,也是设计模式最常用的特性,最关键的问题在于继承的可读性真的没有那么好,尤其还有层数超多的时候,除非是为了封装一些不想见的特性,否则别乱用继承,如果面向对象结合函数式的话,更多的依赖的就不是继承,而是组合,还有就是副作用是客观存在的,函数式编程不是没有副作用,比如读写数据库io操作都是副作用,它只是将副作用收束到一个可控的状态,完全没有副作用的代码是没有用的,就和完全没有耦合的代码是用不了的是一个道理,函数式编程的真正意义不在于少写if else for循环,它最大意义在于改变了人解决问题的思路-----从亲自叫机器“怎么做”,变成叫机器“做什么”,从苦力码农,变成站在更高逻辑层次的观察者。
网友评论