lambda表达式
原创
©著作权归作者所有:来自51CTO博客作者wx5ba8dc11102bc的原创作品,请联系作者获取转载授权,否则将追究法律责任
lambda简介
什么是lambda
- Java8添加的新特性,lambda是一个匿名函数
为什么使用lambda
lambda对接口的要求
- 虽然可以使用lambda可以对某些接口进行简单实现,但是接口中只能定义一个抽象方法不可以多于或者少于一个。
- 在Java8对接口增加了一个新特性:default, 对接口中的方法进行修饰,被修饰的方法在接口中可以有一个默认实现,实现类可以实现也可以不去实现,lambda著名的接口中的方法是必须要实现的,不包含default的部分
@FunctionalInterface
- 这个注解是来修饰函数式接口的(接口中的抽象方法只有一个)
lambda简单使用与之前的方法的比较:
/**
* Created with IntelliJ IDEA.
* Description:
* User: wjx
* Date: 2019-07-02
* Time: 17:33
*/
public class Progras {
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 0;
}
};
//3.使用lambda表达式实现接口
Comparator comparator2 = (a, b)-> a-b;
}
}
class MyComparator implements Comparator{
@Override
public int compare(int a, int b) {
return a-b;
}
}
@FunctionalInterface
interface Comparator{
int compare(int a, int b);
}
基础语法
- 首先定义一系列接口(具体接口的功能和接口的名字相同):
//多参数无返回
@FunctionalInterface
public interface LambdaNoneReturnMutipleParameter {
void test(int a, int b);
}
//无参无返回
@FunctionalInterface
public interface LambdaNoneReturnNoneParameter {
void test();
}
//单参数无返回
@FunctionalInterface
public interface LambdaNoneReturnSingleParameter {
void test(int n);
}
//多参数单返回
@FunctionalInterface
public interface LambdaSingleReturnMutipleParameter {
int test(int a, int b);
}
//无参数单返回
@FunctionalInterface
public interface LambdaSingleReturnNoneParameter {
int test();
}
//单参数单返回
@FunctionalInterface
public interface LambdaSingleReturnSingleParameter {
int test(int n);
}
lambda表达式对上述接口的使用
- 组成:返回值类型(不需要显示的写出来) 参数列表 方法体
- ():用来描述参数列表
- {}:用来描述方法体
- ->:lambda运算符,读作goes to
package interfaces.syntax;
import interfaces.*;
/**
* Created with IntelliJ IDEA.
* Description:
* User: wjx
* Date: 2019-07-02
* Time: 17:53
*/
public class Syntax1 {
public static void main(String[] args) {
//无参无返回
LambdaNoneReturnNoneParameter lambdaNoneReturnNoneParameter1 = () -> {
System.out.println("Hello lambda");
};
//lambda的执行
lambdaNoneReturnNoneParameter1.test();
//无返回值单个参数
LambdaNoneReturnSingleParameter lambdaNoneReturnSingleParameter2 = (int a)->{
System.out.println(a);
};
lambdaNoneReturnSingleParameter2.test(10);
//无返回值多个参数的
LambdaNoneReturnMutipleParameter lambdaNoneReturnMutipleParameter3 = (int a, int b) -> {
System.out.println(a+b);
};
lambdaNoneReturnMutipleParameter3.test(10, 20);
//单个发返回值无参数
LambdaSingleReturnNoneParameter lambdaSingleReturnNoneParameter4 = ()->{
return 100;
};
int result= lambdaSingleReturnNoneParameter4.test();
System.out.println(result);
//有返回值单个参数
LambdaSingleReturnSingleParameter lambdaSingleReturnSingleParameter5 = (int a)->{
return a * 2;
};
int result2 = lambdaSingleReturnSingleParameter5.test(10);
System.out.println(result2);
//有返回值多个参数
LambdaSingleReturnMutipleParameter lambdaSingleReturnMutipleParameter6 = (int a, int b)->{
return a + b;
};
int result3 = lambdaSingleReturnMutipleParameter6.test(10, 20);
System.out.println(result3);
}
}
lambda表达式的语法精简:
- 由于在接口的抽象方法中,已经定义了参数的数量和类型,所以在lambda表达式中参数的类型可以省略,但是如果要省略类型,那么所有参数的类型都要进行省略,不要出现省略一个参数不省略下一个参数
LambdaNoneReturnMutipleParameter lambdaNoneReturnMutipleParameter = (a,
b)->{ System.out.println("Hello world");};
- 如果参数列表中,参数的数量只有一个,此时小括号可以省略
LambdaNoneReturnSingleParameter lambdaNoneReturnSingleParameter = a ->{ System.out.println("hello world");};
LambdaNoneReturnSingleParameter lambdaNoneReturnSingleParameter1 = a ->
System.out.println("hellloworld");
- 如果方法体中,唯一的一条语句是一个返回语句,则省略大括号的同时必须省略return:
LambdaSingleReturnNoneParameter lambdaSingleReturnNoneParameter =
()->10;
LambdaSingleReturnMutipleParameter lambdaSingleReturnMutipleParameter =
(a, b)->a+b;
lambda表达式处理重复代码:
- 在程序中会有很多重复调用的代码,这时候可以写一个函数change(),在需要的地方进行调用,在lambda中把这种方式叫做方法引用
- 方法引用:将lambda的表达式的实现指向一个已经实现的方法,做一个对这个方法的引用
- 语法:方法的隶属者(视方法是否为静态或者非静态变量而定) :: 方法名
- 注意:
- 参数的数量和类型一定要和接口中的定义的方法一致
- 返回值的类型一定要和接口中定义的方法一致
//定义方法
private static int change(int a){ return a * 2;}
//使用lambda表达式
//方法引用,引用了change方法的实现LambdaSingleReturnSingleParameter lambdaSingleReturnSingleParameter1 =
Syntax3::change;
lambda对构造方法的引用:
//lambda对构造方法的引用
public class Person{
public int age;
public String name;
public Person(){
System.out.println("无参");
}
public Person(String name, int age){
this.name= name;
this.age = age;
System.out.println("有参");
}
@Override
public String toString() {
return "Person"+age;
}
}
- 首先定义两个接口,分别是对无参构造函数和有参构造函数的获取
- 在lambda中使用
interface PersonCreater{
Person getPerson();
}
interface PersonCreater1{
Person getPerson(String name, int age);
}
//构造方法的引用
PersonCreater personCreater1 = Person::new;
Person person = personCreater1.getPerson();//结果为无参
//调用有参无参构造函数看的是接口中的方法
PersonCreater1 personCreater11 = Person::new;
Person b = personCreater11.getPerson("wjx", 21);//结果为有参
lambda对集合排序的使用:
//需求:已知在一个ArrayList中有若干个Person对象,将这些Person对象按年龄进行降序排序
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("wjx", 20));
list.add(new Person("wjx1", 21));
list.add(new Person("wjx2", 22));
list.add(new Person("wjx3", 23));
list.add(new Person("wjx4", 24));
list.add(new Person("wjx5", 25));
list.add(new Person("wjx6", 26));
//进入sort源码可以发现 >0 o1>o2 <0 o1<o2 =0 相等
list.sort((o1, o2)-> o2.age - o1.age);
System.out.println(list);
lambda对TreeSet的使用:
//使用lambda表达式来实现Comparator接口,并实例化一个treeset对象
TreeSet<Person> set = new TreeSet<>((o1, o2)->{
if(o1.age>= o2.age){
return -1;
}else{
return 1;
}
});
set.add(new Person("wjx", 20));
set.add(new Person("wjx1", 21));
set.add(new Person("wjx2", 22));
set.add(new Person("wjx3", 23));
set.add(new Person("wjx4", 24));
set.add(new Person("wjx5", 25));
set.add(new Person("wjx6", 26));
lambda对集合的遍历:
ArrayList<Integer> arrayList = new ArrayList<>();
Collections.addAll(arrayList, 1,2,3,4,5,6,7,8,9,0);
//将集合中的每一个元素都带入到方法accept()中
arrayList.forEach(System.out::println);
//输出集合中所有的偶数
arrayList.forEach(ele->{
if(ele%2==0){
System.out.println(ele);
}
});
lambda对集合元素的删除:
//删除集合中年龄大于22的元素
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("wjx", 20));
list.add(new Person("wjx1", 21));
list.add(new Person("wjx2", 22));
list.add(new Person("wjx3", 23));
list.add(new Person("wjx4", 24));
list.add(new Person("wjx5", 25));
list.add(new Person("wjx6", 26));
list.removeIf(ele->ele.age>22);
lambda对线程的操作:
new Thread(()->{
for(int i= 0;i<100;i++){
System.out.println(i);
}
}).start();
系统内置的一些函数式接口:
Predicate<T> : 参数T, 返回值boolean
IntPredicate int -> boolean
LongPredicate long->boolean
DoublePredicate double->boolean
Consumer<T> : 参数指定的T 返回使用void
IntConsumer int->void
LongConsumer long->void
DoubleConsumer double->void
Function<T,R> : 参数为T,返回值R(指定类型的返回值)
IntFunction<R> int->R
LongFunction long->R
DoubleFunction double->R
IntToLongFunction int->long
IntToDoubleFunction int->double
LongRoIntFUnction long ->int
LongTODoubleFunction long->double
DoubleToIntFunction double->int
DoubleToLongFunction double->long
Supplier<T> : 参数T, 返回值T
UnaryOperator继承于Function : 参数T, 返回值T(与参数同类型)
BinaryOperator继承BiFunction : 参数T,T 返回值T
BFunction<T,U, R> : 参数是T和U 返回值是R
BiPredicate<T, U> : 参数T,U 返回值boolean
BiConsumer<T, U> : 参数T, U 返回值void
最常用的
Predicate<T>
Consumer<T>
Function<T>
Supplier<T>
lambda闭包:
private static Supplier<Integer> getNumber(){
int num = 0;
//引用局部变量num
return ()->{return num;};
}
int n = getNumber().get();
- 发现输出为0,但是我们知道方法中的局部变量的生命周期在方法执行完毕后就会销毁,但是因为lambda闭包会提升包围变量的生命周期,因为在其他地方对这个变量多了一个引用(可以获取方法中的局部变量)
- 如果在lambda中是使用某一个局部变量,这个局部变量必须是一个常量,比如这个变量a在编译的时候会加上final。一旦在闭包中使用这个变量,那么这个变量就会变成final