Java技术栈——Java 8的Lambda讲解与应用
目录
- Lambda 表达式和函数式接口
Lambda 表达式
函数式接口
- 与匿名内部类的对比分析
匿名内部类的格式:
函数式变成思想
格式解释
- 注意
- lambda应用
匿名内部类与 Lambda 函数比较
Lambda 表达式和函数式接口
Java8 的 lambda 的使用确实方便了许多,但也使初次了解的人感觉到难以阅读,但是确实是更便于开发,代码更简洁。在 Java8 以前,我们想要让一个方法可以与用户进行交互,比如说使用方法内的局部变量;这时候就只能使用接口做为参数,让用户实现这个接口或使用匿名内部类的形式,把局部变量通过接口方法传给用户。
传统匿名内部类缺点:代码臃肿,难以阅读
Lambda 表达式
Lambda 表达式将函数当成参数传递给某个方法,或者把代码本身当作数据处理;引入了新的操作符 “->” 该操作符把语句分为两步 参数列表+语句块
语法格式
一:无参+无返回值
()-> System.out.println();
二:有参+无返回值
(param)-> Systm.out.println(param); //小括号可以不写
三:多参+有返回值
Comparator com = (x,y)->{
System.out.println("lambda");
return Integer.compare(x,y);
};
四:多参+有返回值(一条语句)
// {}和return均可省略
// 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
另外,在Lambda 表达式中,参数的数据类型可以省略,因为JVM可以通过上下文推断数据类型。如下简单代码示例:
// 不需要参数,返回值为 5
() -> 5
// 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 类型声明(对比)
A a= (int a, int b) -> a + b;
// 不用类型声明
A b= (a, b) -> a - b;
// 大括号中的返回语句
A c= (a, b) -> { return a * b; };
// 没有大括号及返回语句
A d= (a, b) -> a / b;
函数式接口
lambda需要函数式接口的支持 接口只有一个抽象方法的接口 称为函数式接口 @FunctionalInterface。其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
函数式接口的用途:
它们主要用在Lambda表达式和方法引用(实际上也可认为是Lambda表达式)上。如定义了一个函数式接口如下:
lambda需要函数式接口的支持 接口只有一个抽象方法的接口 称为函数式接口 @FunctionalInterface。其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
函数式接口的用途:
它们主要用在Lambda表达式和方法引用(实际上也可认为是Lambda表达式)上。如定义了一个函数式接口如下:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
GreetingService greetService1 = message -> System.out.println("Hello " + message);
greetService1.sayMessage("everyOne");
与匿名内部类的对比分析
匿名内部类的格式:
new 父类或接口() {
重写的方法;
}
在匿名内部类中,有很多内容都是冗余的,比如在使用匿名内部类实现多线程的代码中,因为 Thread 构造方法中需要传递 Runnable 接口类型的参数,所以我们不得不 new Runnable。因为要重写 Runnable 中的 run 方法,所以不得不写了public void run。
整个匿名内部类中最关键的东西是方法,方法中最关键的有前中后三点。
前:参数。
中:方法体
后:返回值
最好的情况是只关注匿名内部类中最核心的这些内容(方法参数,方法体,返回值)如果使用Lambda表达式,可以只关注最核心的内容,Lambda 表达式是匿名内部类的简化写法。
函数式变成思想
Lambda 属于函数式编程思想(在Java这个万物皆对象的面前,都快忘记了面向过程的编程思想)。
面向对象思想:怎么做。
函数式编程思想:做什么。
public class Demo01Inner {
public static void main(String[] args) {
//使用匿名内部类的方式实现多线程。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行了");
}
}).start();
//使用Lambda表达式实现多线程
new Thread(() -> System.out.println(Thread.currentThread().getName() + "执行了")).start();
}
}
匿名内部类可以省去单独创建 .java 文件的操作。但是匿名内部类也是有缺点的,正如前文所说的,写法太冗余了,里面有很多多余的部分。匿名内部类也有简化写法,匿名内部类的简化写法是 Lambda 表达式匿名内部类中最关键的内容是方法的参数,方法体,以及返回值,而在 Lambda 表达式中,关注的就是这三个关键的东西。
格式解释
Lambda 表达式的标准格式:
(参数类型 参数名) -> {
方法体;
return 返回值;
}
小括号中的参数和之前方法的参数写法一样,可以写任意个参数,如果多个参数,要使用逗号隔开。
-> 是一个运算符,表示指向性动作。
大括号中的方法体以及 return 返回值的写法和之前方法的大括号中的写法一样。
Lambda 表达式是函数式编程思想。而函数式编程:可推导,就是可省略。因为在 Thread 构造方法中需要 Runnable 类型的参数,所以可以省略 new Runnable。因为 Runnable 中的只有一个抽象方法 run,所以重写的必然是这个 run 方法,所以可以省略 run 方法的声明部分(public void run)。Lambda 表达式可以省略面向对象中的一些条条框框,让我们只关注最核心的内容。
注意
使用 Lambda 表达式需要注意以下两点:
1.Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
2.Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。
lambda应用
根据员工年龄排序;年龄相同,根据薪资排序;并输出;
Person p = new (age,sallary);
List<Person> list = Arrays.asList(p1, p2, p3, p4······);
//此list无add,remove方法,为Arrays内部定义的List匿名类
//使用lambda表达式进行排序
Collections.sort(list, (o1, o2) -> {
return (Integer.compare(o1.age, o2.age) == 0) ?
(Integer.compare(o1.salary, o2.salary)) : Integer.compare(o1.age, o2.age);
});
//使用lambda表达式输出
list.forEach(o1 -> {
System.out.println(o1.toString());
}
}
}
匿名内部类与 Lambda 函数比较
//使用匿名内部类
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
//使用Lambda表达式
Collections.sort(list, (Student o1, Student o2) -> {
return o1.getAge() - o2.getAge();
});
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(list);
}
作者:菜C++鸡java
来源:CSDN