Lambda表达式
使用举例
1
| Comparator<Integer> com2 =(o1, o2)-> Integer.compare(o1, o2);
|
格式举例
lambda形参列表 ->Lambda方法体
->:Lambda操作符或箭头操作符
->的左边:lambda形参列表,对应着要重写接口中的抽象方法的形参列表
->的右边:lambda体,对应着接口的实现类要重写的方法的方法体
无参,无返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void test(){ Runnable r1 = new Runnable() { @Override public void run() { System.out.println("xixihaha"); } }; r1.run();
Runnable r2 = () ->{ System.out.println("xixihaha"); }; r2.run(); }
|
需要一个参数,但无返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Consumer<String> con = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con.accept("嘻嘻哈哈");
Consumer<String> con1 = (String s) ->{ System.out.println(s); }; con1.accept("嘻嘻哈哈"); }
|
数据类型可以省略,因为可以推断除了,类型推断
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void test4(){ Consumer<String> con1 = (String s) ->{ System.out.println(s); }; con1.accept("xixihaha"); Consumer<String> con2 = (s) -> { System.out.println(s); }; con2.accept("xixihaha"); }
|
若只需要一个参数,参数小括号可以省略
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void test5(){ Consumer<String> con1 = (String s) ->{ System.out.println(s); }; con1.accept("xixihaha"); Consumer<String> con2 = s -> { System.out.println(s); }; con2.accept("xixihaha"); }
|
两个或以上的参数,多条执行语句,并且有返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void test6(){ Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; Comparator<Integer> com2 = (o1,o2) -> { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); }; }
|
当Lambda体只有一条语句时,return与大括号若有,都可以忽略
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void test7(){ Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2); }
|
Lambda表达式本质
- 一方面,lambda表达式作为接口的实现类的对象。
- lambda表达式是一个匿名函数
函数式接口
定义:
常见的函数式接口
消费型接口:Consumer void accept(T t)
供给型接口:Supplier T get()
函数型接口: Function<T,R> R apply(T t)
判断型接口:Predicate boolean test(T t)
Lambda表达式的语法规则总结
->的左边:lambda形参列表,参数的类型都可以省略。形参如果只有一个,则一对()也可以省略
->的右边:lambda体,对应着重写的方法的方法体。如果方法体只有一行执行语句,则一对{}省略
方法引用
举例
Integer :: compare
理解
- 方法引用,可以看作是基于Lambda表达式的进一步刻画
- 当需要提供一个函数式接口的实例时,我们可以使用lambda表达式提供此实例
- 当满足一定条件的情况下,我们还可以使用方法引用或构造器替换lambda表达式
本质
方法引用作为函数式接口的实例
格式
类(或对象)::方法名
具体使用情况说明
Case1: 对象::实例方法
要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值都一致。此时可以考虑使用方法b实现对方法a的替换和覆盖。此替换或覆盖即为方法应用。
注意:此方法b是非静态的方法,需要对象调用
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
|
@Test public void test1(){ Consumer<String> con1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; Consumer<String> con2 = s -> System.out.println(s);
Consumer<String> con3 = System.out::println; con3.accept("hello"); }
@Test public void test2(){ Employee emp = new Emplyoee("alugg",15); Supplier<String> sup1 = new Supplier<String>() { @Override public String get() { return emp.getName(); } }; System.out.println(sup1.get()); Supplier<String> sup2 = ()->emp.getName(); System.out.println(sup2.get()); Supplier<String> sup3 = emp::getName; }
|
Case2: 类::静态方法
要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值都相同(一致)。此时可以考虑使用方法b实现对方法a的替换和覆盖。此替换或覆盖即为方法应用。
注意:此方法b是静态的方法,需要对象调用
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
|
@Test public void test3(){ Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1, o2); Comparator<Integer> com3 = Integer::compare; }
@Test public void test4(){ Function<Double, Long> fun1 = new Function<Double, Long>() { @Override public Long apply(Double aDouble) { return Math.round(aDouble); } }; Function<Double,Long> fun2 = aDouble -> Math.round(aDouble);
Function<Double,Long> fun3 = Math::round; }
|
Case3: 类::实例方法
要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同。
同时,抽象方法a中有n个参数,方法b中有n-1个参数。且抽象方法a的第1个参数作为方法b的调用者,切抽象方法a的后n-1个参数与方法b的n-1个参数类型相同
注意:此方法b是非静态方法,需要对象调用。但是形式上,写出对象a所属的类
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
| @Test public void test6(){ BiPredicate<String, String> biPre1 = new BiPredicate<String, String>() { @Override public boolean test(String s, String s2) { return s.equals(s2); } };
BiPredicate<String, String> biPre2 = (s1,s2) -> s1.equals(s2);
BiPredicate<String, String> biPre3 = String::equals; } @Test public void test7(){ Employee emp = new Emplyoee("alugg",15); Function<Employee, String> fun1 = new Function<Employee, String>() { @Override public String apply(Employee employee) { return employee.getName(); } };
Function<Employee, String> fun2 = emp -> emp.getName();
Function<Employee, String> fun3 = Employee::getName; }
|
构造器引用
格式
类名::new
说明
- 调用了类名对应的类中的某一个确定的构造器
- 具体调用的是类中的哪一个构造器取决于函数式接口函数式接口的抽象方法的形参列表
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
| @Test public void test1(){ Supplier<Employee> sup1 = new Supplier<Employee>(){ @Override public Employee get(){ return new Employee(); } };
Supplier<Employee> sup2 = Employee::new; }
@Test public void test2(){ Function<Integer, Employee> func1 = new Function<Integer, Employee>() { @Override public Employee apply(Integer id) { return new Employee(id); } };
Function<Integer, Employee> func2 = Employee::new; }
@Test public void test3(){ BiFunction<Integer, String, Employee> func1 = new BiFunction<Integer, String, Employee>() { @Override public Employee apply(Integer id, String name) { return new Employee(id, name); } };
BiFunction<Integer, String, Employee> func2 = Employee.new; }
|
数组引用
1 2 3 4 5 6 7 8 9 10 11
| @Test public void test(){ Function<Integer, Employee[]> func1 = new Function<Integer, Employee[]>() { @Override public Employee[] apply(Integer length) { return new Employee[length]; } }; Function<Integer, Employee[]> func2 = Employee[]::new; }
|