参考:
1
2
什么是lambda表达式
-
lambda意为λ,表示是一个函数,而一个函数只有唯一的输入输出映射,因此引出lambda表达式的定义
-
Lambda是一个
唯一匿名方法
-
一个接口,如果只有一个显式声明的抽象方法,那么它就是一个函数式接口。一般用@FunctionalInterface标注出来(也可以不标)
-
因为该接口有一个抽象方法,在new的时候需要@Override这个抽象方法
格式
什么可以省略?
可推断的都可省略,因此尽可能使用泛型
方框中都可以省略
因为在调用这个方法的时候,public int add(int int ) return 都是唯一且确定且必须存在的,因此可以被唯一推断出来,所以可以省略,省略后为
(x,y) -> x+y;
因为只有一行语句,所以代码块{}可省,return可省
1.预定义的函数式接口
在JDK中定义了很多的函数式接口,例如BiFunction接口,就可以传入两个参数,返回一个参数,无需自定义;当然三个传参还是需要自定义的
1.1
函数型接口
1.JDK预定义了很多函数式接口以避免用户重复定义。最典型的是Function
:
1
2
3
4
5@FunctionalInterface public interface Function<T, R> { R apply(T t); }
这个接口代表一个函数,接受一个T类型的参数,并返回一个R类型的返回值。
消费型接口
2.另一个预定义函数式接口叫做Consumer
,跟Function的唯一不同是它没有返回值。
1
2
3
4
5@FunctionalInterface public interface Consumer<T> { void accept(T t); }
供给型接口
3.Supplier
有一个get()方法
1
2
3
4
5@FunctionnallInterface public interface Supplier<T>{ T get(); }
断定型接口
4.还有一个Predicate
断定,用来判断某项条件是否满足。经常用来进行筛滤操作:
1
2
3
4
5@FunctionalInterface public interface Predicate<T> { boolean test(T t); }
1.2函数式接口的测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40public class LambdaTest { public static void main(String[] args) { //1.Runnale接口测试————run() Runnable r = () -> System.out.println("测试"); r.run(); //2.Function接口测试————— T apply(X x) Function<Integer, Integer> fun = (age) -> { System.out.println("年龄为:" + age);//年龄为:21 return age + 1; }; System.out.println("下次过生日的年龄:" + fun.apply(21));//下次过生日的年龄:22 //3.Consumer接口测试————accept(T t) //3.1加泛型,推断s为String类型 Consumer<String> con = (s) -> System.out.println(s + "666666");//双击关注666666 con.accept("双击关注"); //3.2不加泛型需要指定,默认为Object Consumer con2 = (s) -> System.out.println(s + "777777");//养猪厂子777777 con2.accept("养猪厂子"); //4.Supplier接口测试 //4.1不加泛型,则不推断 Supplier sup = () -> { return new Integer(1); }; //4.2加泛型,则可推断返回值为Integer Supplier<Integer> sup2 = () -> 1; //5.Predicate接口测试 Predicate<Integer> pred = (i) -> i > 10; System.out.println(pred.test(11));//ture System.out.println(pred.test(9));//false } }
2.自定义函数式接口
定义函数式接口,接收多个参数
1
2
3
4
5@FunctionalInterface public interface MyFunction<X,Y,Z,T> { T fun(X x,Y y ,Z z); }
使用
1
2
3
4
5
6
7
8
9//6.自定义MyFunction接口 MyFunction<Integer,Integer,Integer,String> myFun = (age,weight,higth) -> "年龄为:" + age + "体重为:" + weight + "身高为:" + higth; String myInfo = myFun.fun(21, 145, 181); System.out.println(myInfo);//年龄为:21体重为:145身高为:181
3.方法引用
- 当实现@FunctionalInterface的函数式接口使用lambda表达式时,
如果方法体直接调用 某个类or对象 的 静态or非静态方法,
且返回值和形参都高度相同or完全相同,那么就可以使用方法引用 编译看左
:类型的推断需要左边函数类的泛型来指定
3.1对象::非静态方法
Function fun = p :: myHight;即把fun中的唯一抽象函数apply() 和 myHight()方法绑定,调用fun.apply(1)相当于调用p.myHight(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class LambdaTest2 { public static void main(String[] args) { //0. People的非静态方法myHight()的形参 和 Function类的apply()方法的形参对应 // 的返回值 和 的返回值对应 People p = new People(21,"张家豪"); //1.用 对象p :: 非静态方法 Function<Integer,String> fun = p :: myHight; //2.此时的fun对象中的apply()方法已经和 p对象中的myHight()方法绑定 System.out.println(fun.apply(181)); } } class People{ int age; String name; public String myHight(Integer hight){ return "my hight is " + hight; }}
3.2类 :: 静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17。。。。。。。。 //编译看左:左边需要指定泛型,才能推断出右边的参数类型 Consumer<Integer> con = People::describe; con.accept(2); } } class People { int age; String name; public static void describe2(Integer i) { System.out.println("People类有" + i + "个属性参数"); System.out.println("一个是name,一个是age"); }
3.3类 :: 实例方法
参考
4.构造器引用
和方法引用类似
构造器的形参 = 函数式接口的抽象方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18Function<String,People> fun1 = s -> new People(s); People p1 = fun1.apply("张豪猪"); Function<String,People> fun2 = People::new; People p2 = fun2.apply("豪猪张"); BiFunction<Integer,String,People> bifun1 = People::new; People p3 = bifun1.apply(21, "豪张猪"); } } @AllConstructor class People { int age; String name;
5.数组引用
数组引用算是构造器引用的一种,可以引用一个数组的构造
1
2
3
4
5
6
7
8
9
10
11
12
13
14Function<Integer,People[]> fun1 = p -> new People[p]; People[] arr1 = fun1.apply(10);//创建一个长度为10的People数组 Function<Integer,People[]> fun2 = People[]::new; fun2.apply(20); } } class People { int age; String name;
区别与总结
1.类型推断
编译看左
有一个People的静态方法 public static void describe(Integer count) {。。}
则必须通过 Consumer <Integer> con = People::describe;
而不能 Consumer con = People::describe;
因为后者不能推断出con.accept()需要什么类型的参数
泛型顺序对应形参顺序
Function<x,y> fun = 是如何确定谁是形参谁是返回值的呢?
- 第一个是形参,第二个是返回值
而此时因为一一对应,Function<Integer,String>一定是Integer为形参,String为返回值
- 》》》当BiFunction<T, U, R> bifun= 时,R是返回值类型,T和U的顺序也已经固定
2.能省则省
凡是能唯一确定推断的都能省略
(s) ->{return 一个语句}
可写为s -> 一个语句
3.代码绑定
例如:
- Function<Integer,String> fun = p :: myHight就是把myHight()方法绑定给了fun.apply()
- Supplier sup = () -> {…return i } ; 则是把{…return i }代码块绑定给sup.get()
4.方法引用和lambda的联系
方法引用本质就是lambda表达式,只是在上一个例子中Supplier<Integer> sup = () -> {.....return i } ;
里面的{.....return i }
如果是被封装到了某一个特定的方法,那么可以直接使用方法引用,而不需要把代码块的内容挨个写出来
5.构造器引用和方法引用的联系
构造器引用本质是方法引用,方法体就是new 一个对象,并返回,因此形如:
但一定要有new
6.数组引用和构造引用的联系
之前的构造引用都是new一个对象,而数组引用是new一个数组,仅此而已,形如:
forEach的lambda表达式
参考
最后
以上就是直率发箍最近收集整理的关于lambda表达式和方法引用什么是lambda表达式格式1.预定义的函数式接口2.自定义函数式接口3.方法引用4.构造器引用5.数组引用区别与总结forEach的lambda表达式的全部内容,更多相关lambda表达式和方法引用什么是lambda表达式格式1.预定义内容请搜索靠谱客的其他文章。
发表评论 取消回复