一、什么是lambda
lambda是java8添加的一个新的特性,是一个匿名函数,使用lambda表达式可以对一个接口进行非常简洁的实现,下面来看一段代码
public class LambdaTest {
public static void main(String[] args) {
//1.使用接口实现类
Comparator comparator = new MyComparator();
//2.使用匿名内部类
Comparator comparator1 = new Comparator() {
@Override
public int compare(int a, int b) {
return a - b;
}
};
//3.使用lambda表达式
Comparator comparator2 = (a, b) -> a - b;
}
}
interface Comparator {
int compare(int a, int b);
}
class MyComparator implements Comparator {
@Override
public int compare(int a, int b) {
return a - b;
}
}
由上面代码可以看出,使用匿名内部类的方式比使用接口实现类方式简单,使用lambda表达式比使用匿名内部类的方式更简单
二、lambda对接口的要求
虽然可以使用lambda表达式对某些接口进行简单的实现,但并不是所有的接口都可以使用lambda表达式来实现,要求接口中定义的必须要实现的抽象方法只能有一个
@FunctionInterface
修饰函数式接口的,接口中的抽象方法只有一个
看下面代码验证:
@FunctionInterface 修饰的接口抽象方法只有一个时,编译通过
@FunctionInterface
修饰的接口抽象方法个数>1,编译不通过
三、lambda基础语法
- () : 用来描述参数列表
- {} : 用来描述方法体
- -> :lambda运算符,读goes to
1 无参无返回值
public class LambdaTest {
public static void main(String[] args) {
//无返回值无参数
LambdaNoReturnNoParam lambdaNoReturnNoParam = () -> {
System.out.println("hello world");
};
lambdaNoReturnNoParam.test();
}
}
@FunctionalInterface
interface LambdaNoReturnNoParam {
void test();
}
2 无返回值单个参数
public class LambdaTest {
public static void main(String[] args) {
//无返回值单个参数
LambdaNoReturnSingleParam lambda2 = (int n) -> {
System.out.println(n);
};
lambda2.test(1);
}
}
@FunctionalInterface
interface LambdaNoReturnSingleParam {
void test(int n);
}
3 无返回值多个参数
public class LambdaTest {
public static void main(String[] args) {
LambdaNoReturnMutipleParam lambda3=(int a,int b)->{
System.out.println(a+b);
};
lambda3.test(1, 2);
}
}
@FunctionalInterface
interface LambdaNoReturnMutipleParam {
void test(int n, int b);
}
4 有返回值无参
public class LambdaTest {
public static void main(String[] args) {
LambdaSingleReturnNoParam lambda = () -> {
return 2;
};
System.out.println(lambda.test());
}
}
@FunctionalInterface
interface LambdaSingleReturnNoParam {
int test();
}
5 有返回值单个参数
public class LambdaTest {
public static void main(String[] args) {
LambdaSingleReturnSingleParam lambda = (int n) -> {
return n;
};
System.out.println(lambda.test(1));
}
}
@FunctionalInterface
interface LambdaSingleReturnSingleParam {
int test(int n);
}
6 有返回值多个参数
public class LambdaTest {
public static void main(String[] args) {
LambdaSingleReturnMutipleParam lambda = (int a, int b) -> {
return a + b;
};
System.out.println(lambda.test(1, 2));
}
}
@FunctionalInterface
interface LambdaSingleReturnMutipleParam {
int test(int n, int b);
}
四、lambda语法精简
1 精简参数类型
由于在接口的抽象方法中,已经定义了参数的数量和类型,所以在lambda表达式中,参数类型可以省略
public class LambdaTest {
public static void main(String[] args) {
LambdaNoReturnMutipleParam lambda = (a, b) -> {
System.out.println(a + b);
};
lambda.test(1, 2);
}
}
@FunctionalInterface
interface LambdaNoReturnMutipleParam {
void test(int n, int b);
}
注:如果需要省略类型,则每一个参数的类型都要省略,千万不要出现省略一个参数,不省略一个参数类型
2 精简参数小括号
如果参数列表中,参数的数量只有一个,此时小括号可以省略
public class LambdaTest {
public static void main(String[] args) {
LambdaNoReturnSingleParam lambda = a -> {
System.out.println(a);
};
lambda.test(1);
}
}
@FunctionalInterface
interface LambdaNoReturnSingleParam {
void test(int n);
}
3 精简方法大括号
如果方法体中只有一条语句,大括号可以省略
public class LambdaTest {
public static void main(String[] args) {
LambdaNoReturnSingleParam lambda = a -> System.out.println(a);
lambda.test(1);
}
}
@FunctionalInterface
interface LambdaNoReturnSingleParam {
void test(int n);
}
如果方法体中唯一的一条语句是一个返回语句,则在省略掉大括号的同时也必须省略掉return
public class LambdaTest {
public static void main(String[] args) {
LambdaSingleReturnNoParam lambda = () -> 10;
System.out.println(lambda.test());;
}
}
@FunctionalInterface
interface LambdaSingleReturnNoParam {
int test();
}
五、lambda语法进阶
1 普通方法引用
方法引用可以快速将一个lambda表达式的实现指向一个已经实现的方法
语法: 方法的隶属着::方法名
方法分为静态的和非静态的,静态方法的常拿类来调用,非静态方法常用对象来调用,所谓方法隶属着视方法而定,比如下面的change方法,它是一个静态方法,那么隶属着指LambdaTest这个类,如果change方法是一个非静态方法,那么隶属着就是LambdaTest这个对象
public class LambdaTest {
public static void main(String[] args) {
LambdaSingleReturnSingleParam lambda = (a) -> change(a);
System.out.println(lambda.test(6));
//方法引用,语法:[方法的隶属着::方法名] 引用了change方法的实现
LambdaSingleReturnSingleParam lambda2=LambdaTest::change;
System.out.println(lambda2.test(7));
}
private static int change(int a){
return a*2;
}
}
@FunctionalInterface
interface LambdaSingleReturnSingleParam {
int test(int n);
}
方法引用中需注意以下亮点
- 参数数量和类型与接口中定义的方法一致
- 返回值类型也一定要和接口定义的类型一致
2 无参构造方法引用
public class ConstructLambdaTest {
public static void main(String[] args) {
PersonCreate c = () -> new Person();
System.out.println(c.getPerson());
//无关构造函数引用
PersonCreate creater = Person::new;
System.out.println(creater.getPerson());
}
}
interface PersonCreate{
Person getPerson();
}
@Data
class Person {
private String name;
private int age;
}
3 含参构造方法引用
public class ConstructLambdaTest {
public static void main(String[] args) {
PersonCreate creater = Person::new;
System.out.println(creater.getPerson("张三", 1));
}
}
interface PersonCreate {
Person getPerson(String name, int age);
}
@Data
class Person {
private String name;
private int age;
public Person(String name, int age) {
}
}
六、lambda综合案例
需求:在ArrayList有若干个Person对象,Person对象有name,age属性
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private String name;
private int age;
}
1 集合排序
将这些Person对象按年龄进行降序排序
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 30));
list.add(new Person("李四", 20));
list.add(new Person("李四", 40));
list.sort(((o1, o2) -> o2.getAge() - o1.getAge()));
System.out.println(list);
2 TreeSet
使用lambda表达式实现Comparator接口,并实例化一个TreeSet对象
注意:treeset相等o1.getAge() - o2.getAge()=0时会自动对元素去重,所以不能让返回为0
TreeSet<Person> set = new TreeSet<Person>((o1, o2) -> {
if (o1.getAge() - o2.getAge() >= 0) {
return -1;
} else {
return 1;
}
});
set.add(new Person("张三", 30));
set.add(new Person("李四", 20));
set.add(new Person("李四", 40));
System.out.println(set);
3 集合遍历
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
//将集合中每一个元素都带入accept方法中
list.forEach(System.out::println);
//输出集合中的偶数
list.forEach(ele -> {
if (ele % 2 == 0) {
System.out.println(ele);
}
});
4 删除集合元素
删除集合中年龄大于20岁的元素
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 30));
list.add(new Person("李四", 20));
list.add(new Person("李四", 40));
//将集合中的每个元素都带入到test方法中,如果返回是true,则删除这个元素
list.removeIf(ele -> ele.getAge() > 20);
System.out.println(list);
5 线程实例化
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}).start();
}
七、系统内置函数式接口
在指定类型的参数,返回值是boolean时可以用Predicate
Predicate 参数是T类型,返回值是boolean
IntPredicate 参数int 返回值boolean
LongPredicate
DoublePredicate
Consumer 参数T 返回值void
IntConsumer
Function<T, R> 参数是T 返回值R(指定类型参数,指定类型返回值)
IntFunction
LongFunction
IntToLongFunction
Supplier 无参 指定类型返回值
UnaryOperator 参数T 返回值T
BiFunction<T, U, R> 参数T U 返回值R
BinaryOperator 参数T T 返回值T
BiPredicate<T, U> 参数T U 返回值boolean
BiConsumer<T, U> 参数T U 返回值void
八、闭包
- 闭包可以提升变量的生命周期,获取某个方法的局部变量
public static void main(String[] args) {
int n = getNumber().get();
System.out.println(n);
}
public static Supplier<Integer> getNumber() {
int num = 10;
//闭包
return () -> num;
}
- 在闭包中引用的变量一定是常量
public static void main(String[] args) {
int a = 10;
Consumer<Integer> c = ele -> {
System.out.println(a);//报错
};
a++;
c.accept(1);
}