背景
JDK8开始引入的函数式编程,大大降低了Java编码的复杂度。它是一种编程范式,即一切都是数学函数。在Java中,函数式编程与lambda表达式密不可分。本文从最基础的编译原理的Statements && Expressions讲起,一步步带你深入浅出函数式编程。
一、Statements && Expressions
语句一般有表达式语句、声明语句、控制流语句,相当于自然语言中的一个句子,一个语句构成一个完整的执行单元。
表达式是由变量、运算符和方法调用组成的,这些变量、运算符和方法调用是根据语言的语法构造的,其计算结果为单个值。
| Statements(语句) | Expressions(表达式) |
| 执行某些操作 | 计算某个值 |
| print("Hello World") | "Hello World" |
| return 666; | 666 |
| if (condition) {...} | condition |
表达式可以是语句的一部分,语句从来不是表达式的一部分;所有表达式都是有类型的。尽管如此,不同的语言对于这些定义会略有不同。既然提到了简单的提到了这些概念,那么Blocks一般由0或者多个statements组成,用Java示例如下,
public static void main(String[] args) { boolean condition = true; if (condition) { // begin block 1 System.out.println("Condition is true."); } // end block one else { // begin block 2 System.out.println("Condition is false."); } // end block 2 }
二、Lambda与函数式编程
Lambda表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
Java里,函数不是第一等公民,需要封装到接口里。从而Java Lambda表达式 --> 内部匿名类。
函数式编程起源于称为函数理论的数学模型和 Lambda 演算中的 lambda。Lambda 表达式利用函数式编程特性。在 Java 中使用 Lambda 最明显的体验是它简化并减少了创建某些构造(例如匿名类)所需的源代码量。
lambda写法上一共两种,如下,经过上一章的铺垫这块大家看起来清晰了吧(手动狗头)。(parameters) -> expressions 或 (parameters) -> { statements; } 代码示例一:
private static void lambda() { IntSupplier integerExpression = () -> 5; IntSupplier intSupplierStatement = () -> { int a = 1; int b = 1; return a + b; }; }
代码实例二:
interface MyLambdaInterface { void doSomeShit(String string); } public static void enact(MyLambdaInterface myLambdaInterface, String string) { myLambdaInterface.doSomeShit(string); } private static void invoke() { enact(string -> System.out.println(string), "Hello World"); }
三、常用的函数式接口
JDK 8 中提供了大量的函数式接口,这些接口定义在java.util.function中,因此我们一般情况下不需再定义自己的接口,同时,各个接口的作用和名字都是相对应的,所以,了解函数式接口的命名模式就是很有必要的了。
较为常见的就这四种,通过简单的代码调用,用法见文识义。
- Supplier->供应商
- Consumer->消费者
- Predicate->断言
- Function->函数
import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; /** * 常用的函数式接口 * Supplier->供应商 * Consumer->消费者 * Predicate->断言 * Function->函数 * * @since 2021-10-22-10:04 AM */ class App { public static void main(String[] args) { // 无输入参数,返回T类型的一个结果。 // public interface Supplier<T> Supplier<String> supplier = () -> "Test supplier"; supplier.get(); // return String | Test supplier // 接受一个T类型的参数,无返回。 // public interface Consumer<T> Consumer<String> consumer = (x) -> { System.out.println(x); }; // Consumer<String> consumer = System.out::println; consumer.accept("Test consumer"); // void | 控制台打印 "Test consumer" // 接受一个T类型的参数,返回布尔值。 // public interface Predicate<T> Predicate<String> predicate = x -> x.contains("predicate"); predicate.test("Test predicate"); // return boolean | true // 接受一个T类型的参数,返回R类型结果。 // public interface Function<T, R> Function<Integer, String> function = x -> "This is Integer:" + x; function.apply(100); // return String | "This is Integer:100" } }
小结
Java作为一种通用编程语言,吸收了函数式范式,在函数式编程中,实现一个函数,该函数是不被包含在一个类中的,这也是面对对象和函数式编程的基本区别。
函数式编程语言里也可以有对象,但通常这些对象都是恒定不变的,一般是参数或者返回值。函数式编程语言里没有 for/next 循环,因为这些逻辑意味着有状态的改变。在函数式编程语言里通过递归、把函数当成参数传递的方式实现循环逻辑。