1、体验方法引用
- 在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作
- 那么考虑一种情况:如果我们在Lanbda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再重复逻辑呢?
- 答案更定是没有必要
- 那我们又是如何已经存在的方案的呢?
- 这就是我们要讲解的方法引用,我们是通过方法引用来使用已经存在的方案
1.1、需求
- 定义一个接口(Printable):里面定义一个抽象方法:void printString(String s);
- 定义一个测试类(PrintableDemo),在测试类中提供两个方法,一个方法是:usePrintable(Printable p),一个方法是主方法,在主方法中调用usePrintable方法
package com.lambda; public class PrintableDemo { public static void main(String[] args) { // usePrintable(new Printable() { // @Override // public void printString(String s) { // System.out.println(s); // } // }); // usePrintable((String s) -> System.out.println(s)); // usePrintable((s) -> System.out.println(s)); // usePrintable(s -> System.out.println(s)); //方法引用符 :: usePrintable(System.out::println);//爱生活爱Java } public static void usePrintable(Printable p) { p.printString("爱生活爱Java"); } } interface Printable { void printString(String s); }
2、方法引用符
::该符号为引用运算符,而它所在的表达式被称为方法引用
回顾一下我们再体验方法引用中的代码 Lambda表达式:usePrintable(s -> System.out.print (s) ); 分析:拿到参数s之后通过Lambda表达式,传递System.out.println方法去处理
方法引用:usePrintable(System.out : : println); 分析:直接使用System.out中的println方法来取代Lambda,代码更加的简洁
3、推导与省略
- 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
- 如果使用方法引用,也是同样可以根据上下文进行推导
- 方法引用是Lambda的孪生兄弟
package com.methodreference; public class PrintableDemo { public static void main(String[] args) { usePrintable(i -> System.out.println(i));//666 usePrintable(System.out::println);//666 } private static void usePrintable(Printable p) { p.printInt(666); } } @FunctionalInterface interface Printable { void printInt(int i); }
4、Lambda表达式支持的方法引用(常见的引用方式)
- 引用类方法
- 引用对象的实例方法
- 引用类的实例方法
- 引用构造器
4.1、引用类方法
- 引用类方法,其实就是引用类的静态方法
- 格式:类名::静态方法
- 范例:Integer ::parseInt Integer类的方法:public static int parseInt(String s)将此String转换为int类型数据
- Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
package com.methodreference; public class ConverterDemo { public static void main(String[] args) { useConverter((s) -> { return Integer.parseInt(s); }); useConverter(s -> Integer.parseInt(s)); //Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数 useConverter(Integer::parseInt); } private static void useConverter(Converter c) { int number = c.convert("100"); System.out.println(number); } } @FunctionalInterface interface Converter { int convert(String s); }
4.2、引用对象的实例方法
引用对象的实例方法,其实就引用类中的成员方法
格式:对象::成员方法
范例:“HelloWorld” ::toUpperCase String类中的方法:public String toUpperCase ( ) 将此String所有字符转换为大写
Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数
package com.methodreference; public class PrinterDemo { public static void main(String[] args) { usePrinter((String s) -> { String result = s.toUpperCase(); System.out.println(result); });//HELLOWORLD usePrinter(s -> System.out.println(s.toUpperCase()));//HELLOWORLD //Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数 usePrinter(new PrintString()::printUpper);//HELLOWORLD } private static void usePrinter(Printer p) { p.printUpperCase("HelloWorld"); } } class PrintString { public void printUpper(String s) { String result = s.toUpperCase(); System.out.println(result); } } interface Printer { void printUpperCase(String s); }
4.3、引用类的实例方法
- 引用类的实例方法,其实就是引用类中的成员方法
- 格式:类名::成员方法
- 范例:String::substring String类中的方法:pubic String subString(int beginIndex,int endIndex),从beginIndex开始到endIndex结束,截取字符串。返回一个字串,字串的长度为endIndex-beginIndex
- Lambda表达式被类的实例方法替代的时候,第一个参数作为调用者,后面的参数全部传递给该方法作为参数
package com.methodreference; public class MyStringDemo { public static void main(String[] args) { useMyString((s, x, y) -> { return s.substring(x, y); });//llo useMyString((s, x, y) -> s.substring(x, y));//llo /** * Lambda表达式被类的实例方法替代的时候 * 第一个参数作为调用者 * 后面的参数全部传递给该方法作为参数 */ useMyString(String::substring);//llo } private static void useMyString(MyString my) { String s = my.mySubString("HelloWorld", 2, 5); System.out.println(s); } } @FunctionalInterface interface MyString { String mySubString(String s, int x, int y); }
4.4、引用构造器
- 引用构造器,其实就是引用构造方法
- 格式:类名::new
- 范例:Student::new
- Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数
package com.methodreference; public class StudentDemo { public static void main(String[] args) { useStudentBuilder(((name, age) -> { return new Student(name, age);//Student{name='小明', age=23} })); useStudentBuilder((name, age) -> new Student(name, age));//Student{name='小明', age=23} //Lambda表达式被构造器替代的时候,它的形式参数全部给构造器作为参数 useStudentBuilder(Student::new);//Student{name='小明', age=23} } private static void useStudentBuilder(StudentBuilder s) { Student student = s.build("小明", 23); System.out.println(student); } } class Student { private String name; private Integer age; public Student() { } public Student(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } @FunctionalInterface interface StudentBuilder { Student build(String name, int age); }