一,什么是lambda表达式
1.1 函数式接口
要想了解什么是lambda表达式,就必须得知道什么是函数式接口,函数式接口是指只包含一个抽象方法的接口。如果我们自己写一个函数时接口,最好在接口前添加@Functionallnterface,和@Override具有类似的作用,可以检查我们所写的接口是否正确。例如:
@FunctionalInterface
interface One{// 可以有其他的字段和方法,但是只能有一个抽象方法
void test();
}
1.2 lambda表达式的语法
(parameters) -> expression 或 (parameters) -> { statements;}
parameter : 方法中的参数列表,这里的方法指的是函数式接口中的抽象方法,注意这里的参数可以不写类型(要么全都写参数类型,要么全都不写参数类型)。
expression(表达式)/statements(代码块) : 是函数式接口中抽象方法的具体实现。
注意:
- 参数类型可以省略。
- 如果参数列表中只有一个参数,() 可以省略。
- 如果方法体中只有一条语句,那么{}可以省略。
- 如果方法体中只有一条语句,且该语句是return语句,要么添加{},要么省略return。
- 如果参数列表中没有参数,()不可以省略。
二,lambda表达式的使用
可以说,lambda表达式是匿名内部类的一种简写形式,但是还是有一定的区别,lambda表达式所需要的函数式接口只能有一个抽象方法,匿名内部类所需要的接口可以有多个抽象方法。
2.1 无返回值无参
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public class Demo {
public static void main(String[] args) {
NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn() {
@Override
public void test() {
System.out.println("无参数");
}
};
//这两个语句的内容一样,上面是用匿名表达式,下面是用lambda表达式
NoParameterNoReturn noParameterNoReturn1 = () -> System.out.println("无参数");
}
}
2.2 无返回值一个参
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
public class Demo {
public static void main(String[] args) {
OneParameterNoReturn oneParameterNoReturn
= (a) -> System.out.println("a");
//或 = a -> System.out.println("a");
}
}
2.3 无返回值多个参
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
public class Demo {
public static void main(String[] args) {
MoreParameterNoReturn moreParameterNoReturn
= (a,b) -> System.out.println(a+b);
//或 = (int a, int b) -> System.out.println(a+b);
}
}
2.4 有返回值无参数
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
String test();
}
public class Demo {
public static void main(String[] args) {
NoParameterReturn noParameterReturn
= () -> "hello";
//注:无参时,()不能省略
}
}
2.5 有返回值一个参数
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
public class Demo {
public static void main(String[] args) {
OneParameterReturn oneParameterReturn
= (a) -> {return a;};
//或 = a -> a;
}
}
2.6 有返回值多个参数
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
public class Demo {
public static void main(String[] args) {
MoreParameterReturn moreParameterReturn
= (a,b) -> a + b;
//或 = (a,b) -> {return a+b;};
}
}
三,变量捕获
匿名内部类和lambda表达式中的变量捕获只适用于局部变量!!!
3.1 匿名内部类
当在匿名内部类中引用外部类的局部变量时,这个局部变量必须声明为final或者实际上为final(即只赋值一次)。这是因为匿名内部类的实例可能会在外部方法执行完毕之后才被创建和使用,如果内部类可以修改外部局部变量,就可能导致不可预期的结果。
interface Str{
void print();
}
public class Demo2 {
public static void main(String[] args) {
int a = 10;
Str str = new Str() {
@Override
public void print() {
//a = 20;这样写会报错
System.out.println(a);
}
};
str.print();
}
}
3.2 lambda表达式
在Lambda表达式中,可以访问的外部变量必须是隐式final或者实际上为final(即只在赋值一次)。
interface A{
void eat();
}
public class Demo3 {
public static void main(String[] args) {
int b = 10;
A a = () -> {
b = 3;
System.out.println(b);
};
a.eat();
}
}
注意:
- 尽管我们可以在Lambda表达式中访问外部变量y,但不允许在Lambda表达式中重新声明具有相同名称的变量。
- 捕获的变量在Lambda表达式中是被复制的而不是被引用,这意味着如果外部变量在Lambda表达式外部发生了变化,那么Lambda表达式内部捕获的变量值不会受到影响。
四,Lambda在集合当中的使用
对应的接口 | 新增的方法 |
Collection | removeIf() spliterator() stream() paralleStream() forEach() |
List | replaceAll() sort() |
Map | getOrDeflaut() forEach() replaceAll() putIfAbsent() remove() raplace() ...... |
4.1 forEach()
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class Demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.print(integer +" ");
}
});
System.out.println();
list.forEach((x)-> System.out.print(x + " "));
}
}
4.2 sort()
import java.util.ArrayList;
import java.util.List;
public class Demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(10-i);
}
list.forEach((x)-> System.out.print(x + " "));
System.out.println();
list.sort((o1, o2) -> o1 - o2);
list.forEach((x)-> System.out.print(x + " "));
}
}
lambda表达式使代码更加简洁,但同时使代码的可读性变差,且不易调试