Java函数式编程入门指南:从基础到实践,掌握函数式编程技巧
1. 前言

最近变得忙碌起来了,用于写东西的时间逐渐减少。这几日在 Java 开发过程中开始尝试运用函数式编程风格。因此就创作一些小的内容来进行分享。
2. 什么是函数式编程?
在我看来,函数式编程的特点是将函数当作一等公民来运用。通常我们在开发过程中主要是在对数据进行处理。在面向对象的编程里,主要是在对类进行处理。而在函数式编程中,不是在编写函数,就是在前往编写函数的途中。接下来我们一起看看 Java 中函数式编程的发展历程。我小时候曾玩过一种价格低廉的黑白屏游戏机,那时只能玩俄罗斯方块,这种游戏机是不具备可扩展性的。
public void playGame(){
// 只能玩俄罗斯方块
这种机器给童年带来了许多乐趣。后来小伙伴拥有了一台 gameboy,这台掌机的优势在于能够插卡。一张卡对应一个游戏,其中最为著名的就是《超级马里奥》和《打砖块》。此时,这台机器具备了完全可扩展的特性。
公共的 void 方法 playGameboy,该方法接收一个 GameboyCard 类型的参数 card。
card.getGame().run()
卡的价格很贵,即便可以扩展,当时购买卡的渠道也很少。那时就曾想,要是能自己制作 gameboy 游戏就好了(接着就开始搞编程?)。理想中的游戏机是,我们不在意游戏的风格,只要能将符合接口的游戏卡放入其中,并在该游戏机中运行即可。
所以我们定义了一个固定的游戏卡接口:
/**
* @author Felordcn
* @since 2019/10/31 22:13
*/
@FunctionalInterface
public interface Card {
Game apply();
只要符合这种接口的游戏卡都能插到机器中玩:
/**
* Fun.
* @param card the card
*/
void fun(Card card) {
Game game = card.apply();
game.run();
熟练面向对象的同学会说,这就是面向接口编程吧?是的,你说得没错。然而,这里的 Card 接口只做一件事,那就是提供游戏。我们的重心是游戏卡吗?显然不是!有趣好玩的游戏才是我们的目的。所以,不管它是卡,还是光碟,甚至是网络,只要能给我们提供游戏以供娱乐,都符合我们的需求。
// 玩插卡游戏机
fun(() -> new CardGame());
// 玩 PSP
fun(() -> new PSPGame());
// more
作为码农,平常我们都在进行 SQL 的编写。无论是大厂还是小厂,无论是单体系统还是分布式系统。SQL 能够帮助我们处理很多业务关系。对于 SELECT、INSERT、UPDATE、DELETE 这每一种命令,只要是符合 SQL 规范的数据库,无论是什么表,其操作都是一致的。你声明了何种命令,就会执行何种操作。这时数据和函数处于松耦合的状态。这种特点使得我们能够做到“万变不离其宗”。这也是一种不同寻常的函数式编程方式。
3. 面向对象和函数式编程冲突吗?
面向对象一直处于这样的范式中:我能操作什么数据,以及这种数据该怎么操作。函数式编程则一直沉浸于给我提供操作数据的方法。面向对象的最大优点包括多态性和封装;函数式编程的优势在于抽象化和声明式命令风格。两者实际上是正交的,是可以互补的,能够在同一程序中共同存在。争论面向对象好还是面向函数好,就如同争论哪门语言好一样,都是非常极端的。面向对象方面:存在的东西未必都是对象,而函数可以是对象;函数式编程方面:存在的情况并不总是纯粹的,副作用是真实存在的。总之,面向对象注重分解,函数编程注重组合。
4. 函数式编程特点
函数风格的编程拥有自己的一些特点:
5. 总结
今天我对函数式编程表达了一些简单的理解。对于习惯了面向对象的 Java 开发者而言,理解函数式编程并非易事。它不只是拥有 Lambda 和匿名函数!更多的是一种思想。在此推荐一个很棒的 Java 函数式编程库 vavr 。有兴趣的同学可以去学习一下。