为什么使用Lambda表达式?(做为初学者接触这个新的语法,会很懵逼,说道理,我在接触到这一块的时候,语法规则我看到了也很懵逼,因为这个和逻辑的关系不是很大,但就是作为一种新的语法出现,一时间很难接受。所以,只要我们多加练习,熟悉了就会接受了,记住,要多加练习!!就像你和一个刚刚学习Java的人来说,你和他说100遍地Hello world 的格式,他也不会写,这个需要自己去敲。)
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简介、更灵活的代码。作为一种更为紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda表达式:在Java8语言中引入的一种新的语法元素和操作符。这个操作符为 “->” ,该操作符被称为Lambda操作符或箭头操作符。它将Lambda分为两个部分:
左侧:指定了Lambda表达式需要的参数列表。
右侧:指定了Lambda体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能。
Lambda表达式的本质:接口的具体实现类的实现对象。
那么接下来介绍Lambda表达式的六种语法格式:
在介绍学习之前,先看一些例子,感受一下Lambda表达式。还是,要多加练习,慢慢地我们就会习惯。
在学习Lambda表达式之前,我们学过Compared
1 Comparator<Integer> com1 = new Comparator<Integer>() { 2 3 @Override 4 public int compare(Integer o1, Integer o2) { 5 return Integer.compare(o1, o2); 6 } 7 }; 8 9 int compar1 = com1.compare(12, 21); 10 System.out.println(compar1);
再将它改为Lambda表达式写法:
1 Comparator<Integer> com2 =(o1,o2) ->Integer.compare(o1, o2);
2 int compar2 = com2.compare(41, 21);
3 System.out.println("lambda表达式写法:"+compar2);
我们会发现很神奇,本来一大段地代码,Lambda表达式一行搞定。
1、语法格式一:无参,无返回值。
1 // lambda格式一 无参无返回值的 2 @Test 3 public void test1() { 4 Runnable r = new Runnable() { 5 @Override 6 public void run() { 7 System.out.println("改之前: 这是lambda格式一修改之前无参无返回值的输出结果"); 8 } 9 }; 10 11 r.run(); 12 13 System.out.println("**************************"); 14 15 Runnable r1 = () -> { 16 System.out.println("改之后: 这是lambda格式一修改之后无参无返回值的输出结果"); 17 }; 18 19 r1.run(); 20 }
2、语法格式二:Lambda表达式需要一个参数,但是没有返回值。
1 // lambda格式一 带参无返回值的 2 @Test 3 public void test2() { 4 Consumer<String> c = new Consumer<String>() { 5 @Override 6 public void accept(String s) { 7 System.out.println(s); 8 } 9 }; 10 c.accept("改之前: 这是lambda格式二修改之前带参无返回值的输出结果"); 11 12 System.out.println("************************"); 13 14 Consumer<String> c1 = (String s2) -> { 15 System.out.println(s2); 16 }; 17 c1.accept("改之后: 这是lambda格式二修改之后带参无返回值的输出结果"); 18 }
3、语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”。
1 // lambda格式三 类型推断 2 @Test 3 public void test3() { 4 Consumer<String> c1 = (s2) -> { 5 System.out.println(s2); 6 }; 7 c1.accept("改之后: 这是lambda格式三对格式二优化类型推断之后带参无返回值的输出结果"); 8 } 9 10 //类型推断举例理解 11 @Test 12 public void test4(){ 13 List<String> list = new ArrayList<>();//类型自动推断 14 int[] arr = {1,2,3};//类型自动推断 15 }
4、若Lambda表达式只需要一个参数的时候,参数的小括号可以省略。
1 //格式四 当lambda只需要一个参数的时候,参数小括号可以省略 2 @Test 3 public void test5(){ 4 //1 5 Consumer<Integer> con = new Consumer<Integer>() { 6 @Override 7 public void accept(Integer i) { 8 System.out.println("格式四修改之前:"+(i+4)); 9 } 10 }; 11 con.accept(5); 12 13 System.out.println("**************"); 14 Consumer<Integer> con1 = i -> { 15 System.out.println("格式四修改之后:"+(i+4)); 16 }; 17 con1.accept(6); 18 19 }
5、语法格式五:Lambda表达式需要两个或者两个以上的时候,多条执行语句,并且可以有返回值。(小括号不能省略)
1 //格式五 lambda需要2个或者2个以上的参数 多条执行语句,并且可以有返回值 2 @Test 3 public void test6(){ 4 Comparator<Integer> com = new Comparator<Integer>() { 5 @Override 6 public int compare(Integer o1, Integer o2) { 7 System.out.println(o1); 8 System.out.println(o2); 9 return o1.compareTo(o2); 10 } 11 }; 12 System.out.println(com.compare(12, 21)); 13 14 System.out.println("*********************"); 15 Comparator<Integer> com1 = (o1,o2) ->{ 16 System.out.println(o1); 17 System.out.println(o2); 18 return o1.compareTo(o2); 19 }; 20 System.out.println(com1.compare(12, 6)); 21 }
6、语法格式六:当Lambda体只有一条语句的时候,return与大括号若有,都可以省略。
1 //格式六 对于lambda体而言,lambda体只有一条语句,return和大括号都可省略 2 @Test 3 public void test7(){ 4 Comparator<Integer> com1 = (o1,o2) ->{ 5 return o1.compareTo(o2); 6 }; 7 System.out.println(com1.compare(6, 6)); 8 9 System.out.println("****************"); 10 Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2); 11 System.out.println(com2.compare(12, 6)); 12 }
什么是函数式(Function)接口?
只包含一个抽象方法的接口,称之为函数式接口。
你可以通过Lambda表达式来创建该接口的对象,(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明。) @FunctionlInterface 注解
Java内置的四大核心函数式接口:
1、Consumer
1 @Test 2 public void test1(){ 3 happyTime(500.0, new Consumer<Double>() { 4 5 @Override 6 public void accept(Double doubled) { 7 System.out.println("今天去了一趟天上人间,消费"+doubled); 8 } 9 }); 10 11 System.out.println("**************"); 12 happyTime(400.0, money -> System.out.println("今天去了一趟天上人间,消费"+money)); 13 } 14 15 public void happyTime(Double money,Consumer<Double> con){ 16 con.accept(money); 17 }
2、Supplier
1 @Test 2 public void test6(){ 3 Student s1 = new Student(); 4 Function<Student, String> fun = s -> s.getName(); 5 System.out.println(fun.apply(s1)); 6 7 8 } 9 10 11 //学生类 12 13 package com.wyh.方法引用; 14 15 /** 16 17 * 创建时间:2019年12月11日 下午5:22:16 18 19 * 项目名称:practise13_JAVA8新特性 20 21 * @author WYH 22 23 * @version 1.0 24 25 * @since JDK 1.8.0 26 27 * 文件名称:Student.java 28 29 * 类说明: 30 31 */ 32 33 public class Student { 34 private String name = "王友虎"; 35 private int age = 22; 36 public String getName() { 37 return name; 38 } 39 public void setName(String name) { 40 this.name = name; 41 } 42 public int getAge() { 43 return age; 44 } 45 public void setAge(int age) { 46 this.age = age; 47 } 48 49 50 } 51 52
3、Function
1 @Test 2 public void test4(){// 3 4 //Math类中有个静态方法round() 四舍五入,取整数部分 5 Function<Double,Long> fun = d -> Math.round(d); 6 System.out.println(fun.apply(500.25)); 7 }
4、Predicate
1 @Test 2 public void test7(){ 3 Predicate<String> pre = s -> s.equals("abc"); 4 System.out.println(pre.test("abc")); 5 }
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
方法引用可以看作是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
要求:实现接口的抽象方法的参数列表和返回值类型相同,必须与方法引用的方法参数列表和返回值类型保持一致。(针对于接下来说的情况1和情况2)
格式:使用操作符 “::”将类(或对象)与方法名分割开来
具体分为如下的三种情况:
情况1 对象::非静态方法
情况2 类::静态方法
情况3 类::非静态方法(较为难理解)
情况1:
1 @Test 2 public void test1(){ 3 Consumer<String> con = s -> System.out.println(s); 4 con.accept("北京欢迎你"); 5 6 System.out.println("方法引用方式一 对象::非静态方法****************"); 7 8 PrintStream pin = System.out; 9 Consumer<String> con1 = pin::println; 10 con1.accept("这个是方法引用。。"); 11 } 12 13 @Test 14 public void test2(){ 15 Object obj = new Object(); 16 Supplier<Class> sup = () -> obj.getClass(); 17 System.out.println(sup.get()); 18 19 System.out.println("方法引用方式一 对象::非静态方法***********"); 20 21 Supplier<Class> sup2 = obj::getClass; 22 System.out.println(sup2.get()); 23 24 }
情况2:
1 @Test 2 public void test3(){ 3 Comparator<Integer> com = (t1,t2) -> Integer.compare(t1,t2); 4 System.out.println(com.compare(12, 21)); 5 6 System.out.println("方法引用方式二 类::静态方法**************"); 7 Comparator<Integer> com1 = Integer::compare; 8 System.out.println(com1.compare(21, 21)); 9 } 10 11 @Test 12 public void test4(){// 13 14 //Math类中有个静态方法round() 四舍五入,取整数部分 15 Function<Double,Long> fun = d -> Math.round(d); 16 System.out.println(fun.apply(500.25)); 17 18 System.out.println("方法引用方式二 类::静态方法**************************"); 19 Function<Double,Long> fun1 = Math::round; 20 System.out.println(fun1.apply(500.65)); 21 }
情况3:
1 @Test 2 public void test5(){ 3 Comparator<String> com = (t1,t2) -> t1.compareTo(t2); 4 System.out.println(com.compare("abc", "cbd")); 5 6 System.out.println("方法引用方式三 类::非静态方法********************"); 7 //如果一个方法有两个参数,调用方法的时候,其中有一个参数去调方法的时候,我们可以将这个参数看作为一个类,然后观察这个参数的数据类型,改变成方法引用如下 8 Comparator<String> com1 = String::compareTo; 9 System.out.println(com1.compare("abc", "cbd")); 10 } 11 12 @Test 13 public void test6(){ 14 Student s1 = new Student(); 15 Function<Student, String> fun = s -> s.getName(); 16 System.out.println(fun.apply(s1)); 17 18 Function<Student, String> fun1 = Student::getName; 19 System.out.println(fun1.apply(s1)); 20 }