简介
函数式编程是一种编程思想,并且被很多当今主流的编程语言所纳入实现对应的 库和API 供开发者调用
大部分语言都支持的函数式编程三套件:Map、Reduce、Filter
同时在分布式系统课程的第一节 MapReduce 中也经由 Map 和 Reduce 函数的实现中提到了一些函数式编程的思想
核心思想
函数式编程的核心思想是描述 做什么 而不是 怎么做
在函数式编程中,函数被视为第一类对象,可以作为参数传递给其他函数,也可以从其他函数返回
例如下面这段 Java 代码
1 2 3
| List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.forEach(number -> System.out.println(number));
|
1 2 3
| Function<Integer, Integer> square = x -> x * x; System.out.println(square.apply(5));
|
通过 Function 接口实例化了一个不同寻常意义的函数,这个函数接收输入并且输出输入的平方
JDK8 中引入了 Function 这个函数式接口,引入了函数对象,可以说是用面向对象的方式来处理函数式编程的核心
纯函数
函数式编程的其中一个核心概念是纯函数
纯函数的意思是:
- 输出的结果只和输入参数有关
- 函数没有任何副作用(这里的副作用是指不修改除了函数之外的任何变量)
纯函数举例
1 2 3 4 5 6 7 8 9 10
| public class LambdaTest { int idx; public int pureFunctionAddOne(int num){ return num+1; } public int notPureFunctionAddOne(int num){ idx += num+1; return idx; } }
|
函数式接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @FunctionalInterface public interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
static <T> Function<T, T> identity() { return t -> t; } }
|
可以看到在 Function 接口中只有一个抽象方法,剩下的都是这种有且只有一个抽象方法的接口叫做函数式接口
这里的 @FunctionalInterface
起到了一个标注作用,针对这个注解修饰的接口,编译器会强制检查该接口是否满足函数式接口的要求:“确实有且仅有一个抽象方法”,否则将会报错。
即使不使用该注解,只要一个接口满足函数式接口的要求,那它仍然是一个函数式接口,使用起来都一样。该注解只起到标记接口,指示编译器对其进行检查的作用
其他的函数式接口
Function
最常见的以及最核心的函数式接口:java.util.function.Function
,Function
接口表示一个接受单个参数并返回单个值的函数(方法)
在上面的例子中我们也提到过,这里再看一下:
1 2 3
| Function<Integer, Integer> square = x -> x * x; System.out.println(square.apply(5));
|
这里的 Lambda表达式就是相当于一个匿名实现类,相当于是
1 2 3 4 5 6 7 8 9 10
| public class SquareFunction implements Function<Integer,Integer>{ @Override public Integer apply(Integer x) { return x*x; } public static void main(String[] args){ Function<Integer,Integer> square = new SquareFunction(); System.out.println(square.apply(5)); } }
|
Map
有点类似 Map Reduce 中提到的 Map 和 Reduce 函数了
JDK8 Stream API 中的 map 方是接收一个参数,并返回一个值的函数
1
| stream.map((value) -> value.toUpperCase())
|
实际应用
缓存查询
实现一个通用的缓存模板。查询一个值,先找缓存,找到则返回,没找到通过接口获取,结果保存到缓存后返回