说在前面
如果要理解函数式编程, 可能首先要理解什么是函数, 函数在数学上的定义是两组飞空集合的映射, 写法上我们常见 f(x), 这里的 f 就是 function的意思, x就是函数的参数. 举个栗子, f(x) = 2x, 那这个函数的映射就代表了一组 x 和 2乘以x 的映射, 具体点就是, 1对应2, 2对应4, 1.5对应3.
编程中的函数
上面的定义一般大家只要能记起来自己高中学的东西, 就很容易理解, 同时, 应该也能记起来一些常见的函数, 例如, 三角函数等, 同样也有很多复杂的函数分类, 再到大学, 我们学过很多其他复杂的函数, 比如一些变换, 傅里叶变换, 正交变换等等. 等等!!! 我到底想说什么, 其实我想说的是, 复杂的函数, 我们在使用时不会过分关心它是如何实现的(考研的话你还是关心一下).
此时, 我们站在的是函数使用者的角度看问题. 那么, 如果你是函数使用者, 你其实不关心函数的实现, 而只关心这个函数的作用, 比如你要求10的平方, 那你只需要在计算器上按 "".
编程中的函数
那么, 理解了上面的一堆我的瞎BB, 那么接下来我们看看真正编程中, 作为使用者的角度, 如何看待函数. 比如, 给定一个java8 默认函数有很多, 比如
@Test
void testFilter() {
IntStream.rangeClosed(1, 10)
.filter(x -> x % 2 == 0)
.forEach(System.out::println);
}
这是一个简单的打印 1到10 的偶数的方法, 如何从函数的思想理解这个过程? 我们拆解一下这个函数:
- IntStream.rangeClosed(1, 10)
这个如何用使用者的角度理解? 回头看看上面的解释, 这里我们想要的就是一个 1 到 10 的集合, 以往我们可能会写一个方法, 比如一个简单版本的list:
private List<Integer> createArray(){
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
return list;
}
那么现在, 这一步并不是没有实现, 而是被java8实现过了, 你作为使用者的角度, 只需要调用 rangeClosed(1, 10), 和你按计算器没本质的区别.
- .filter(x -> x % 2 == 0)
理解了上面的例子, 那么就好理解下面这个函数了, 它就是一个过滤器, 过滤掉奇数, 不同的是, 这次是你自己定义过滤条件, 但是过滤函数实际是java8提供给你的, 如果用传统的编程方式, 简单的实现就会变成:
private List<Integer> dofilter(@NotNull List<Integer> source) {
for (Iterator<Integer> iterator = source.iterator(); iterator.hasNext(); ) {
int x = iterator.next();
if (x % 2 != 0) {
iterator.remove();
}
}
return source;
}
此时,我们只需要给出 x % 2 != 0, 看到这估计聪明的你应该明白为啥单个方法的接口叫函数式接口了,因为这里的比如filter函数, 那它就是一个参数为判断条件IntPredicate的函数, 如果不明白就自己点进源代码看一下
- .forEach(System.out::println)
这个forEach 和我们平时的 for 循环一样, 但是它的函数定义是以某种方式IntConsumer消费提供的int参数, 这里我们消费的方式就是打印, 你也可以做点爱做的事也可以. - 连连看
很容易看出, 这时的函数, 是 点点点的形式, 就是说 IntStream.rangeClosed(1, 10)完一个点, .filter(x -> x % 2 == 0) 完一个点, 再最后来个.forEach(System.out::println) 打印. 这个例子中的点, 其实就是返回一个可以继续使用方法的对象, 类似建造模式, 你往往会返回this, 接下来你只要build点点点, 而后一个函数的参数, 就是前一个函数的返回, 当然也可能有其他参数, 这个你得自己多看看, 不单是编程语言自己提供的函数, 也有你自己定义的函数, 在这例子中, 那入参都是上一个函数的返回. - 四不像的编程
PrimitiveIterator.OfInt iterator = IntStream.rangeClosed(1, 10).iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
这个例子, 很明显, IntStream.rangeClosed(1, 10) 已经可以拿来继续操作, 但由于开发人员,,不熟悉函数编程, 那么就会导致, 一半寻求使用函数, 一半使用传统编程方式.
对比
传统编程方式, 我们习惯了,写一个函数,然后定义参数,定义返回值,再给定一个实现. 但是函数式编程, 我们往往只需要给定一个实现就可以了, 上面的例子, 过滤时, 你只要给条件即可.
网友评论