目录
函数式编程
函数式编程是一种编程范式,除了函数式编程之外还有 命令式编程,声明式编程 等编程范式。
1. 命令式编程
命令式编程 是面向计算机硬件的抽象,有变量、赋值语句、表达式、控制语句等,可以理解为 命令式编程就是冯诺伊曼的指令序列。 它的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么。
比如,我们要查找数组 numList 中大于5的所有数字,需要这样告诉计算机:
- 创建一个存储结果的集合变量 results
- 遍历这个数字集合 numList;
- 一个一个地判断每个数字是不是大于 5,如果是就将这个数字添加到结果集合变量 results 中。
let results = [];
for(let i = 0; i < numList.length; i++){
if(numList[i] > 5){
results.push(numList[i])
}
}
2. 声明式编程
声明式编程 是以 数据结构的形式来表达程序执行的逻辑。它的主要思想是 告诉计算机应该做什么,但不指定具体要怎么做。SQL 语句就是最明显的一种声明式编程的例子,例如:
SELECT * FROM table_a WHERE num > 5;
以上内容参考自: 什么是「函数式编程」? - 知乎
3. 那什么是 函数式编程呢?
函数式编程
而函数式编程和声明式编程是有所关联的,因为他们思想是一致的:即只关注做什么而不是怎么做。但函数式编程不仅仅局限于声明式编程。
函数式编程的特点
- 函数是一等公民
- 函数是纯函数
的确这个概念听起来很晦涩! 但是我要是说,如果我们定义的一个方法,方法参数是确定的某个数据类型,或者对象,只有这种类型。没有其他的。
但是函数式编程,就允许方法参数是传入一个 函数。
比如看这一段代码:
getSupplier() 这个方法的参数,本来是要求传一个 Supplier的对象进去的。这里把函数当做普通类型一样使用。
也就是说的 函数是一等公民
// b. 使用Lambda表达式 【getSupplier 这里把一段方法当做参数传入进去了!】
String s1 = getSupplier(()->{
return "织女";
});
函数是纯函数
纯函数是指相同的输入总会得到相同的输出,并且不会产生副作用的函数。纯函数的两个特点:
- 相同的输入必有同输出
- 没有副作用
无副作用 指的是函数内部的操作不会对外部产生影响(如修改全局变量的值、修改 dom 节点等)。
这里涉及到一下概念:
函数合成(compose)
函数柯里化(Currying)
高阶函数
... ...
4. java语言中的函数式编程
java自从 jdk1.8后引入了 函数式编程,那我们想想他为什么要引入这种编程模型呢?
java语言中的函数式编程样例
4.1 Supplier 模型 —— 生产数据
// 1. a、Supplier接口无参数,有返回值
// b、Supplier接口返回数据的数据类型根据泛型传递的数据类型决定。
@FunctionalInterface
static interface Supplier<String> {// Supplier接口无参数,有返回值
String get();
}
static class Supper {
public static void main(String[] args) {
Supper supper = new Supper();
supper.test();
}
public void test (){
// a. 调用示例 ,通过匿名内部类来调用
String s3 = getSupplier(new Supplier<String>() {
@Override
public String get() {
return "牛郎";
}
});
// b. 使用Lambda表达式 【getSupplier 这里把一段方法当做参数传入进去了!】
String s1 = getSupplier(()->{
return "织女";
});
System.out.println("s3:" + s3);
System.out.println("s1:" + s1);
}
private String getSupplier(Supplier<String> supplier) {
return supplier.get();
}
}
/
/
/
/
/
4.2 Consumer 模型 —— 消费数据
//2. a、Consumer接口是有参数无返回值。
// b、Consumer接口参数数据类型为泛型传递的数据类型。
@FunctionalInterface
static interface Consumer<String> {
void accept(String str);
// Consumer<String> andThen(Consumer<String> other);
}
static class Consume {
public static void main(String[] args) {
Consume consume = new Consume();
consume.test("abcdefg");
}
public void test(String str){
// a. 使用匿名内部类
reverse(str, new Consumer<String>() {
@Override
public void accept(String s) {
String r = new StringBuffer(s).reverse().toString();
System.out.println(r);
}
});
// b. 使用Lambda表达式 【reverse 这里把一段方法当做参数传入进去了!】
reverse(str, (String s)->{
String r = new StringBuffer(s).reverse().toString();
System.out.println(r);
});
useAndThen(str,
(String s)->{
String r = s.toUpperCase();
System.out.println(r);
},
(String s)->{
System.out.println(s.length());
});
}
public static void reverse(String str, Consumer<String> consumer){
consumer.accept(str);
}
public static void useAndThen(String str, Consumer<String> con1, Consumer<String> con2){
// con1.andThen(con2).accept(str);
con1.accept(str);
con2.accept(str);
}
}
///
///
///
///
///
///
4.3 Predicate 模型 —— 数据判断
@FunctionalInterface
static interface Predicate<String> {
boolean test(String str);
}
static class Predic {
public static void main(String[] args) {
Predic predic = new Predic();
predic.test("abcd");
}
public void test (String str){
// a. 方法的调用 : 使用匿名内部类方式
boolean b1 = usePredicate(str, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() > 6;
}
});
System.out.println("b1:" + b1);
// b. 使用Lambda表达式 【usePredicate 这里把一段方法当做参数传入进去了!】
boolean b2 = usePredicate(str, (t) -> {
return t.length() > 6;
});
System.out.println("b2:" + b2);
}
public static boolean usePredicate(String s, Predicate<String> pre){
return pre.test(s);
}
}
4.4 Function 模型 —— 数据的转换
上面这三种都可以认为是这种的变异过来
@FunctionalInterface
static interface Function<Stirng, Integer> {
Integer apply(String s);
}
static class Fun {
public static void main(String[] args) {
Fun fun = new Fun();
fun.test("abcdef");
}
public void test(String str){
// a. 调用方法示例: Lambda表达式 【function1 这里把一段方法当做参数传入进去了!】
Integer t = function1(str, (s) -> {
return s.length();
});
System.out.println("t: " + t);
// b. 调用方法示例:
Integer r = function1(str, new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
System.out.println("r: " + r);
}
// 创建方法示例:
public static Integer function1(String s, Function<String, Integer> fun){
Integer n = fun.apply(s);
return n;
}
}
结束语:
上面只是简单的,介绍了java语言中的函数式编程,其实还有更高级的用法和含义。今天我们就到这里,下期我们再来介绍下。