目录
1. 为什么要使用Lambda
Lambda 表达式是 JDK 8 中⼀个重要的新特性,lambda 表达式允许通过表达式来代替功能接⼝(通过表达式通过实现业务功能)。lambda 表达式就和⽅法⼀样,它提供了⼀个正常的参数列表和⼀个使⽤这些参数的主体(body,可以是⼀个表达式或⼀个代码块),Lambda 表达式(Lambda expression)可以看作是⼀个匿名函数。
1. 提供了更简单的语法和写代码的⽅式。
2. 取代匿名内部类。
3. 简化代码,⼲净整洁。
2. Lambda语法
Lambda 表达式的基本语法如下:
(参数列表) -> {业务代码实现}
表达式由 3 部分组成:
1. 参数列表:类似⽅法中的形参列表,这⾥的参数是函数式接⼝⾥的参数。这⾥的参数类型可以明确的声明也可不声明⽽由JVM隐含的推断。另外当只有⼀个推断类型时可以省略掉圆括号。
2. -> 表示被用于,不可以省略 。
3. 代码实现:可以是表达式也可以代码块,是函数式接⼝⾥⽅法的实现。代码块可返回⼀个值或者什么都不反回,这⾥的代码块块等同于⽅法的⽅法体。如果是表达式,也可以返回⼀个值或者什么都不返回。
3. Lambda基础使用
import java.util.Arrays;
import java.util.List;
public class LambdaExample {
public static void main(String[] args) {
List<String> lists = Arrays.asList("Hello", "World", "Java");
// 没使⽤ lambda 之前
for (String list : lists) {
System.out.println(list);
}
System.out.println();
// 使⽤ lambda 之后
lists.forEach(s -> System.out.println(s));
}
}
// 输出: hello world Java
hello world Java
注意事项:
1. 如果 lambda 参数的⼩括号⾥⾯只有⼀个参数,那么⼩括号可以省略。
2. 如果⽅法体当中只有⼀句代码,那么⼤括号可以省略。
3. 如果⽅法体中只有⼀条语句,其是 return 语句,那么⼤括号可以省略,且去掉 return 关键字。
4. Lambda和函数式接口
Lambda 表达式的写法:
// 1. 不需要参数 , 返回值为 2() -> 2// 2. 接收⼀个参数 ( 数字类型 ), 返回其 2 倍的值x -> 2 * x// 3. 接受 2 个参数 ( 数字 ), 并返回他们的和( x , y ) -> x + y// 4. 接收 2 个 int 型整数 , 返回他们的乘积(int x , int y ) -> x * y// 5. 接受⼀个 string 对象 , 并在控制台打印 , 不返回任何值 ( 看起来像是返回 void)(String s ) -> System . out . print ( s )
Lambda 表达式不能直接使⽤,它在使⽤之前必须初始化,lambda 表达式必须借助函数式接⼝
(@FunctionalInterface)来初始化。
4.1 函数式接口
函数式接⼝定义:⼀个接⼝有且只有⼀个抽象⽅法。
注意事项:
1. 如果⼀个接⼝只有⼀个抽象⽅法,那么该接⼝就是⼀个函数式接⼝。
2. 如果我们在某个接⼝上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接⼝的定义来要求该接⼝,这样如果有两个抽象⽅法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接⼝中只有⼀个抽象⽅法,你可以不加这个注解。加上就会⾃动进⾏检测的。
函数式接⼝的定义代码如下:
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
有了函数式接⼝之后,我们就可以使⽤ lambda 表达式对其实例化了,实现代码如下:
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
public class LambdaExample {
public static void main(String[] args) {
// lambda 表达式借助函数式接⼝初始化
MyFunctionalInterface functionalInterface = (objects) -> {
for (Object o : objects) {
System.out.println(o.toString());
}
};
// 执⾏ lambda 表达式
functionalInterface.myMethod("张三", "李四", "王五");
}
}
// 输出: 张三 李四 王五
5. Lambda的变量获取
在 lambda 中,如果要获取外部的 变量,那么这个变量要么是被 final 修饰,如果不是被 final 修饰的,要保证在使⽤之前,没有修改,否则就会报错。
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
public class LambdaExample {
public static void main(String[] args) {
int count = 10;
MyFunctionalInterface functionalInterface = (objects) -> {
// count = 99; // 在使⽤之前,如果修改就会报错
for (Object o : objects) {
System.out.println(o.toString());
}
System.out.println("打印外部变量:" + count); // 可以正常执⾏
};
functionalInterface.myMethod("张三", "李四", "王五");
}
}
6. Lambda在集合中的使用
Lambda 表达式最有价值的作⽤就是可以配合集合⼀块使⽤。
Lambda 可以配合使⽤的⽅法列表如下:
6.1 Map 中的 forEach
在没有 Lambda 之前,我们要循环 Map 的实现代码如下:
import java.util.HashMap;
import java.util.Map;
public class LambdaExample {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap() {{
put("name", "Java");
put("desc", "Good");
}};
// jdk 8 之前的写法
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
// 输出: name : Java desc : Good
有了 lambda 之后,我们可以这样写:
import java.util.HashMap;
public class LambdaExample {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap() {{
put("name", "Java");
put("desc", "Good");
}};
map.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
// 输出: name : Java desc : Good
6.2 List 排序
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class LambdaExample {
public static void main(String[] args) {
List<Integer> lists = new ArrayList() {{
add(1);
add(5);
add(3);
add(2);
add(6);
}};
System.out.println(lists); // 排序前顺序 [1, 5, 3, 2, 6]
lists.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; // 正序
}
});
System.out.println(lists);
}
}
// 输出: 1 5 3 2 6 1 2 3 4 5 6
6.3 List 查找
List<String> lists = new ArrayList<String>() {{
add("Java");
add("MySQL");
add("Spring");
}};
List<String> javaItem = lists.stream()
.filter(s -> s.equals("Java")).collect(Collectors.toList());
System.out.println(javaItem);
// 输出: [Java]
7. Lambda优缺点
优点:
1. 代码简洁,开发迅速
2. ⽅便函数式编程
3. ⾮常容易进⾏并⾏计算
4. Java 引⼊ Lambda,改善了集合操作
缺点:
1. 代码可读性变差
2. 在⾮并⾏计算中,很多计算未必有传统的 for 性能要⾼
3. 不容易进⾏调试