Lambda表达式
函数式编程思想
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。
- 相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。
-
面向对象的思想:
做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情. -
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程.
冗余的Runnable代码
public class lambdaDemo {
public static void main(String[] args) {
// 匿名内部类 传统写法
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行");
}
};
new Thread(runnable).start();
//使用lambda表达式方法
Runnable runnable1 = () -> {
};
new Thread(runnable1).start();
//使用方法优化
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程执行");
}
});
//lambda优化写法 使用匿名类部类 并不需要中间的Runnable对象,而是直接得出结果-->函数式编程思想
new Thread(()->System.out.println("多线程任务执行")).start();
}
}
使用实现类
要启动一个线程,需要创建一个 Thread 类的对象并调用 start 方法。而为了指定线程执行的内容,需要调用 Thread 类的构造方法:
package lambda_de;
/**
* @author lx
* @date 2019/1/27 - 16:45
*/
class Lambda_demo2 implements Runnable{
@Override
public void run() {
System.out.println("多线程任务执行");
}
}
public class Test{
public static void main(String[] args) {
Lambda_demo2 demo2 = new Lambda_demo2();
new Thread(demo2).start();
}
}
匿名内部类的好处与弊端
一方面,匿名内部类可以帮我们省去实现类的定义;另一方面,匿名内部类的语法稍微复杂一点.
仔细分析该代码中的语义, Runnable 接口只有一个 run 方法的定义:
public abstract void run();
即制定了一种做事情的方案(其实就是一个函数):无参数:不需要任何条件即可执行该方案。
无返回值:该方案不产生任何结果。
代码块(方法体):该方案的具体执行步骤。
同样的语义体现在 Lambda 语法中,要更加简单
() -> System.out.println("多线程任务执行!")
- 前面的一对小括号即 run 方法的参数(无),代表不需要任何条件;
- 中间的一个箭头代表将前面的参数传递给后面的代码;
- 后面的输出语句即业务逻辑代码;
Lambda标准格式
(参数类型 参数名称) -> { 代码语句 }
- 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
- -> 是新引入的语法格式,代表指向动作。
- 大括号内的语法与传统方法体要求基本一致
使用Lambda标准格式(无参无返回)
//创建cook厨子接口,内含唯一的抽象方法makeFood,无参数无返回值.
public interface Cook {
void makeFood();
}
//创建测试类
public class Demo05InvokeCook {
public static void main(String[] args) {
// TODO 请在此使用Lambda【标准格式】调用invokeCook方法 }
private static void invokeCook(Cook cook) {
cook.makeFood();
}
}
//使用lambda表达式
public static void main(String[] args) {
invokeCook(() -> {
System.out.println("吃饭啦!");
});
}
lambda有参数和返回值
需求:
使用数组存储多个Person对象
对数组中的Person对象使用Arrays的sort方法通过年龄进行升序排序
package lambda_de;
/**
* @author lx
* @date 2019/2/26 - 15:55
*/
public class Person implements Comparable{
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//比较对象属性大小时方法二,比较对象实现comparable接口,并重写compareTo方法
@Override
public int compareTo(Object o) {
int result=0;
Person person;
if (o != null) {
person =(Person)o;
return person.getAge()-age;
}
return result;
}
}
package lambda_de;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author lx
* @date 2019/2/26 - 16:04
*/
public class Compare_demo{
public static void main(String [] args){
Person[] p ={
new Person("陈奕迅",29),
new Person("林志颖",35),
new Person("吴亦凡",32),
};
//(参数1,参数2) - > 函数的运算
Comparator<Person> comparator= (o1, o2) -> o1.getAge()-o2.getAge();
//排序
Arrays.sort(p,comparator);
for (Person ps:p
) {
System.out.println(ps);
}
}
}
Lambda的使用前提
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一 时,才可以使用Lambda。
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
- 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。