lambda表达式与函数式接口初步介绍
何为Lambda表达式?
Lambada:In programming Languages such as Lisp、python and Ruby Lambda is an operator used to denote anonymous functions or closures,following the usage of lambda calculus.
为何需要Lambda表达式?
- 在Java中我们无法将函数作为参数传递给一个方法也无法声明返回一个函数的方法
- 在Javascript中函数作为参数与返回值的情况非常常见,javascript是一门典型的函数式语言 (也是一门面向对象的语言)
例如如下代码在jdk8之前是不存在的:
a.execute(callback(event){
...
})
Lambda表达式基本结构:
(param, param2, param3) -> {
}
注:在这里我们暂时将lambda表达式理解为三部分:参数、分隔符、执行体。
首先我们看一个小例子,如下代码是jdk8之前的风格:
public class SwintTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JButton btn = new JButton();
btn.addActionListener(new ActionListener() { //关键看此处
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("点击了按钮");
}
});
btn.setText("按钮");
frame.setVisible(true);
frame.pack();
frame.add(btn);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
在对比下Jdk8的编程风格:
public class SwintTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JButton btn = new JButton();
btn.addActionListener(event -> System.out.println("点击了按钮")); //关键看此处
btn.setText("按钮");
frame.setVisible(true);
frame.pack();
frame.add(btn);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
之前我们向按钮安装监听器的方式都是传递一个匿名内部类,这其实很没必要我们真正关心的只是actionPerformed方法中的内容而已,但在Jdk8之前没办法只能这样做。而在Jdk8之后我们不需要再传递匿名内部类了,我们可以直接用Lambda表达式来做作为参数。这里看到event是不是有点疑惑,它没有声明类型,这是因为java编译系统可以智能的推导出类型所以我们把类型省略了而已。
写上类型也没有关系,只是没必要而已如:
(ActionEvent event) -> System.out.println("点击了按钮")
如果要打印多条语句则:
btn.addActionListener((ActionEvent event) -> {
System.out.println("点击了按钮-1");
System.out.println("点击了按钮-2");
System.out.println("点击了按钮-3");
});
我们再看另一个例子:
public class Test1 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
//jdk1.4中的循环方式
for (int i = 0; list != null && i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("----------------");
//jdk1.5增强型for循环方式
for (Integer i : list) {
System.out.println(i);
}
System.out.println("----------------");
//jdk1.8的循环方式
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
}
}
Consumer也是Jdk1.8新增加的接口,并且它是函数接口,那么什么是函数接口呢?
函数接口也是jdk1.8新增加的概念,关于函数式接口我们需要知道如下几个知识点:
- 函数式接口可用lambda表达式、方法引用、构造器引用来创建 (暂时了解就行)
- 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
- 如果我们在某个接口上声明了FunctionInterface注解,那么编译器就会按照函数式接口的定义要求该接口 (参考@Override)
- 如果某个接口只有一个抽象方法,但我们并没有给该接口声明FunctionInterface注解,那么编译器依旧将该接口看作是函数式接口
对于符合函数式接口定义的接口我们最好加上@FunctionInterface既方便代码阅读也避免出现与此相关的代码问题,例如一个不符合函数式接口定义的接口有@FunctionInterface声明的话,那么IDE就会提示你该接口不符合函数式接口定义,这样在编码阶段就能够避免出现与此相关的代码问题。