1.一段话理解函数式编程
首先说一下函数
和方法
的区别,简单的可以理解为同一个东西,都是一个执行块。前者是面向过程
的叫法,后者是面向对象
的叫法。所以说函数式编程某种程度上来说也可以理解为方法编程。而写过js的同学应该知道,在js中的函数是允许把另外一个函数作为自身参数的。后来仔细看了《java8实战》,谈一下自己的理解。函数式编程这个概念就是让我们用一种新的思维方式去写java。
2.举个栗子
我们先定义一个简单的People
接口。
public interface People {
void say();
}
然后定义一个ZhangSan
类,当我们需要创建People
实例的时候,显然需要去实现这个接口里的方法。
public class ZhangSan {
People zhangsan = new People() {
@Override
public void say() {
System.out.println("i am zhangsan");
}
};
}
同样的,创建一个LiSi类,也需要这么操作。
public class LiSi {
People liSi = new People() {
@Override
public void say() {
System.out.println("i am lisi");
}
};
}
发现问题了吗?每次创建接口对象的时候,“=”右边的格式是固定的。再者我们创建接口的目的是什么?是为了使用他的方法。那么可以直接使用他的方法而不创建实例吗?java8是这么做的。把上面代码重复的部分改为:() ->
所以上面的代码也可以写成
public class LiSi {
static People liSi = () -> {
System.out.println("i am lisi");
};
}
我们可以尝试调用一下liSi的say方法。
public class LiSi {
static People liSi = () -> {
System.out.println("i am lisi");
};
public static void main(String[] args) {
liSi.say();
}
}
输出结果: i am lisi
其中 () 是参数列表,这里没有使用参数。 ->是操作符,固定格式不必纠结,{}是方法体。
看到这里你可能会有一点疑惑,我们在定义liSi这个对象的时候,也没有指定它的say方法啊,为什么调用say方法的时候可以实现呢?这就涉及到函数式接口的定义:有且仅有一个抽象方法
。所以在创建lisi的时候,方法体里实现的就是People接口里的say方法。当方法体里只有一个表达式的时候,方法体的大括号也可以省略不写
。就像这样:
static People liSi = () -> System.out.println("i am lisi");
我们通常通过 @FunctionalInterface
来标示一个函数式接口,也可以不写,它只是起到一个标示作用。
此时lisi就是一个People对象,且实现了唯一的抽象方法
。现在有一个talk
方法,需要Peopeo参数:
public static void talk(People people) {
people.say();
}
note 我们在调用的时候就可以用
lambda表达式进行替换【理解这一点非常重要,搞清楚这个很方便接下来学习lamda的常用方法和流式编程】:
public static void main(String[] args) {
talk(() -> System.out.println("i am lisi"));
}
因为talk
方法需要的参数是People,而我们的() -> System.out.println("i am lisi")
则正是一个实现了People接口唯一抽象方法的实例。此时运行则会输出:i am lisi
。
理解这一点则可以开始接下来的学习,lambda常用方法
链接: