1、冗余的Lambda场景
- 在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿什么参数做什么操作。
- 那么考虑一种情况:如果我们在Lambda中所指定的操作方案,已经有地方在相同方案,那是否还有必要再写重复逻辑?
package com.methodreference; public class MethodReference { public static void main(String[] args) { printString((s) -> System.out.println(s)); /** * 分析: * Lambda表达式的目的,打印参数传递的字符串 * 把参数s,传递给了System.out对象,调用out对象中的方法println对字符串进行了输出 * 注意: * 1.System.out对象是已经存在的 * 2.println方法也是已经存在的 * 所以我们可以使用方法引用来优化Lambda表达式 * 可以使用System.out方法直接引用(调用)println方法 */ printString(System.out::println); } public static void printString(Printable p) { p.print("HelloWorld"); } } @FunctionalInterface interface Printable { void print(String s); }
2、方法引用符
- 双冒号::为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
3、语义分析
例如上例中,System.out对象中有一个重载的println(String)方法恰好九四我们所需要的。那么对于printString方法的函数式接口参数,对比下面两种写法,完全等效:
- Lambda表达式写法:s -> System.out.println(s);
- 方法引用写法:System.out : : println
- 第一种语言是指:拿到参数之后经Lambda之手,继而传递给System.out.println方法去处理。
- 第二种等效写法的语义是指:直接让System.out中的println方法来取代Lambda。两种写法的执行效果完全一样,而第二种方法引用的写法复用了已有方案,更加简介。
注意:Lambda中传递的参数一定是方法引用中的哪个方法可以接收的类型,否则会抛出异常
4、通过对象名引用成员方法
- 通过对象名引用成员方法
- 使用前提是对象名是已经存在的,成员方法也是已经存在
- 就可以使用对象名来引用成员方法
package com.methodreference; public class Demo01ObjectMethodReference { public static void main(String[] args) { printString(s -> { MethodRerObject obj = new MethodRerObject(); obj.printUpperCaseString(s); }); /** * 使用方法引用优化Lambda * 对象是已经存在的MethodRerObject * 成员方法也是已经存在printUpperCaseString * 所以我们可以使用对象名引用成员方法 */ MethodRerObject obj = new MethodRerObject(); printString(obj::printUpperCaseString); } public static void printString(Printable p) { p.print("Hello"); } } @FunctionalInterface interface Printable { void print(String s); } class MethodRerObject { public void printUpperCaseString(String str) { System.out.println(str.toUpperCase()); } }
5、通过类名引用静态成员方法
- 通过类名引用静态成员方法
- 类已经存在,静态成员方法也已经存在
- 直就可以通过类名接引用静态成员方法
package com.methodreference; public class Demo01StaticMethodReference { public static int method(int number, Calcable c) { return c.calsAbs(number); } public static void main(String[] args) { int method = method(-10, (number) -> { return Math.abs(number); }); System.out.println(method);//10 /** * 使用方法引用优化Lambda * Math类是存在的 * abs计算绝对值的静态方法也是已经存在的 * 所以我们可以直接通过类名引用静态方法 */ int number2 = method(-20, Math::abs); System.out.println(number2);//20 } } interface Calcable { int calsAbs(int number); }
6、通过super引用父类的成员方法
package com.methodreference; interface Greetable { void greet(); } class Human { public void sayHello() { System.out.println("Hello我是Human!"); } } public class Man extends Human { @Override public void sayHello() { System.out.println("Hello我是Man!"); } public void method(Greetable g) { g.greet(); } public void show() { // method(() -> { // Human h = new Human(); // h.sayHello(); // }); /** * 因为有子父类关系,所以存在的一个关键字super,代表父类, * 所以我们可以直接使用super调用父类的成员方法 */ // method(()->{ // super.sayHello(); // }); /** * 使用super引用类的成员方法 * super是已经存在的 * 父类的成员方法sayHello也是已经存在的 * 所以我们可以直接使用super引用父类的成员方法 */ method(super::sayHello); } public static void main(String[] args) { new Man().show(); } }
7、通过this引用本类的成员方法
package com.methodreference; public class Husband { public void buyHouse() { System.out.println("河南二环内买一套四合院!"); } public void marry(Richable r) { r.buy(); } public void soHappy() { // marry(()->{ // this.buyHouse(); // }); /** * 使用方法引用优化Lambda表达式 * this是已经存在的 * 本类的成员方法buyHouse也是已经存在的 * 所以我们可以直接使用this引用本类的成员方法buyHouse */ marry(this::buyHouse);//河南二环内买一套四合院! } public static void main(String[] args) { new Husband().soHappy(); } } @FunctionalInterface interface Richable { void buy(); }
8、类的构造器引用
package com.methodreference; public class Person { private String name; public Person() { } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @FunctionalInterface interface PersonBuilder { Person builderPerson(String name); } class Demo { public static void printName(String name,PersonBuilder pb) { Person person = pb.builderPerson(name); System.out.println(person.getName()); } public static void main(String[] args) { printName("小明", (String name) -> { return new Person(name); });//小明 /** * 使用方法引用优化Lambda表达式 * 构造方法new Person(String name)已知 * 创建对象已知 new * 就可以使用Person引用new创建对象 */ printName("小红",Person::new);//小红 } }
9、数组的构造器引用
package com.methodreference; import java.util.Arrays; public class Demo { public static int[] crateArray(int length,ArrayBuilder ab) { return ab.builderArray(length); } public static void main(String[] args) { int[] arr1 = crateArray(10, (length -> { return new int[length]; })); System.out.println(arr1.length); /** * 使用方法引用优化Lambda表达式 * 已知创建的就是int[]数组 * 数组的长度也是已知的 * 就可以使用方法引用 * int[] 引用new,根据参数传递的长度来创建数组 */ int[] arr2 = crateArray(20, int[]::new); System.out.println(Arrays.toString(arr2)); System.out.println(arr2.length); } } @FunctionalInterface interface ArrayBuilder { int[] builderArray(int length); }