一.Lambda表达式简介
Lambda 表达式是 Java 8 的一个新特性,Lambda 表达式可以代替一部分的匿名内部类,可以使代码变的更加简洁紧凑。
Lambda 表达式只能实现函数式接口,什么是函数式接口呢?就是一个接口有且只有一个抽象方法。函数式接口可以添加 @FunctionalInterface 注解,非函数式接口添加 @FunctionalInterface 注解后,编译会报错。
二.Lambda表达式语法
(parameters) -> expression
或
(parameters) -> { statements; }
- paramaters:类似于方法的形参列表,这里指的是函数式接口中抽象方法的参数。参数的类型即可以声明也可以省略,如果只有一个参数,括号也可以省略
- ->:类似于 JavaScript 中的箭头函数
- 方法体:函数式接口中抽象方法的实现。如果方法体只有一个语句,大括号是可以省略
三.Lambda表达式基本使用
1.无参数无返回值
public class Demo15 {
interface NoParameterNoReturn {
// 无参数无返回值
void test();
}
public static void main(String[] args) {
NoParameterNoReturn noParameterNoReturn = () -> {
System.out.println("无参数无返回值");
};
noParameterNoReturn.test();
}
}
执行结果:
无参数无返回值
Process finished with exit code 0
2.有参数无返回值
public class Demo16 {
interface OneParameterNoReturn {
// 一个参数无返回值
void test(String str);
}
interface TwoParameterNoReturn {
// 两个参数无返回值
void test(String str1, String str2);
}
public static void main(String[] args) {
// 一个参数时,括号阔以省略
OneParameterNoReturn oneParameterNoReturn = str -> {
System.out.println(str);
};
oneParameterNoReturn.test("一个参数无返回值");
TwoParameterNoReturn twoParameterNoReturn = (str1, str2) -> {
System.out.println(str1 + str2);
};
twoParameterNoReturn.test("两个参数", "无返回值");
}
}
执行结果:
一个参数无返回值
两个参数无返回值
Process finished with exit code 0
3.无参数有返回值
public class Demo17 {
interface NoParameterHasReturn {
// 无参数有返回值
String test();
}
public static void main(String[] args) {
// 如果方法体只有一个表达式,大括号可以省略
// 如果主体只有一个表达式返回值则编译器会自动返回值,return 关键字可以省略
NoParameterHasReturn noParameterHasReturn = () -> "无参数有返回值";
System.out.println(noParameterHasReturn.test());
}
}
执行结果:
无参数有返回值
Process finished with exit code 0
4.有参数有返回值
public class Demo18 {
interface OneParameterHasReturn {
// 一个参数有返回值
String test(String str);
}
interface TwoParameterHasReturn {
// 两个参数有返回值
String test(String str1, String str2);
}
public static void main(String[] args) {
// 如果方法体只有一个表达式,大括号可以省略
// 如果主体只有一个表达式返回值则编译器会自动返回值,return 关键字可以省略
OneParameterHasReturn oneParameterHasReturn = (str) -> str;
System.out.println(oneParameterHasReturn.test("一个参数有返回值"));
TwoParameterHasReturn twoParameterHasReturn = (str1, str2) -> {
String result = str1 + str2;
return result;
};
System.out.println(twoParameterHasReturn.test("两个参数", "有返回值"));
}
}
执行结果:
一个参数有返回值
两个参数有返回值
Process finished with exit code 0
四.Lambda表达式变量作用域
- Lambda 表达式相当于一个匿名内部类,匿名内部类只能使用被 final 修饰的局部变量。Lambda 表达式中使用的局部变量可以不用声明为 final,但是必须不可被后面的代码修改,即隐性的具有 final 的语义。
public class Demo19 {
interface TestScope {
void test();
}
public static void main(String[] args) {
// 定义一个局部变量
int age = 18;
TestScope testScope = () -> {
// 可以使用局部变量,但是不能修改其值
System.out.println("局部变量 age = " + age);
};
testScope.test();
}
}
- 在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者变量。
五.集合中Lambda表达式的应用
在 Java 1.8 中给集合新增了很多方法,方法的参数类型是函数式接口,所以在使用这些方法时,可以大量使用 Lambda 表达式,让我们的代码更简洁紧凑。
接口 | 新增方法 |
Iterable | |
Collection | |
List | |
| |
Map | |
| |
| |
| |
| |
| |
| |
|
1.List的forEach使用
通过查看源码,forEach 方法接收一个 Consumer 类型的参数,Consumer 是一个函数式接口,里面只有一个 accept 的抽象方法,所以我们可以通过 Lamdba 表达式实现 Consumer 接口。
代码示例:
public class Demo20 {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
strings.add("1");
strings.add("2");
strings.add("3");
// 使用 forEach 遍历 List 集合
strings.forEach(str -> System.out.println(str));
}
}
执行结果:
1
2
3
Process finished with exit code 0
2.Map的merge使用
通过查看源码,merge 方法接收三个参数,一个 key,一个 value,一个 BiFunction 类型的参数,BiFunction 是一个函数式接口,里面只有一个 apply 的抽象方法,所以我们可以通过 Lamdba 表达式实现 BiFunction 接口。
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
// 从 map 中获取 key 的值
V oldValue = get(key);
// 如果 key 在 map 中不存在,则直接把传进来的 value 赋值给 newValue
// 如果 key 在 map 中存在,则调用 BiFunction 的 apply 方法计算出 newValue 的值
// 传个BiFunction 的 apply 方法的参数,一个是从 map 中取出的值,一个是传入的 value
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if (newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
代码示例:
没有使用 merge 方法实现的代码
public class Demo21 {
public static void main(String[] args) {
// 统计该字符串中各个字符出现的次数
String str = "abcdehaakdhfnzczxhhiaepfasdczkba";
HashMap<Character, Integer> hashMap = new HashMap<>();
for (char c : str.toCharArray()) {
Integer integer = hashMap.get(c);
if (integer != null) {
hashMap.put(c, integer + 1);
} else {
hashMap.put(c, 1);
}
}
hashMap.forEach((key, value) -> {
System.out.println(key + "出现了" + value + "次");
});
}
}
使用 merge 方法实现的代码
public class Demo21 {
public static void main(String[] args) {
// 统计该字符串中各个字符出现的次数
String str = "abcdehaakdhfnzczxhhiaepfasdczkba";
HashMap<Character, Integer> hashMap = new HashMap<>();
for (char c : str.toCharArray()) {
// hashMap.merge(c, 1, (a, b) -> {
// return a + b;
// });
// Integer::sum 等价于上面的写法
hashMap.merge(c, 1, Integer::sum);
}
hashMap.forEach((key, value) -> {
System.out.println(key + "出现了" + value + "次");
});
}
}
两种方式的执行结果是一致的
a出现了6次
b出现了1次
c出现了1次
Process finished with exit code 0
上述列表中还有很多方法,这里就不一一举例说明了!!!大家如果感兴趣,可以自己动手敲一敲,同时,欢迎大家在评论区留言,一起讨论 Lambda 表达式。