方法引用
一、什么是方法引用
- 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
- 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
- 要求:实现接口的抽象方法的參数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
- 格式:使用操作符 “:” 将类(或对象)与方法名分隔开来。
- 如下三种主要使用情况:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
二、使用情境
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
三、使用格式
类(或对象):: 方法名
四、使用方法
1. 对象::实例方法名
1.1.1 代码演示(对象::实例方法名)
//情况一:
//对象::实例方法
//Consumer 中的void accept(T t)
//PrintStream 中的void println(T t)
@Test
public void test1() {
//Lambda表达式使用
Consumer con1 = str -> System.out.println(str);
con1.accept("北京");
System.out.printn("****************");
//方法引用的使用
PrintStream ps = System.out;
Consumer con2 = ps::println;
con2.accept("beijing");
}
1.1.2 代码解读
由前面的定义可知,当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用。
那么上面的代码当中Consumer的accept(T t)方法要执行的是println()语句,可是我们发现println()语句早就已经有实现的方法了,那就是Sysout.out
所以,我们发现这代码示例符合方法引用的定义,即要传递给Lambda体的操作,已经有实现的方法。由此,我们的方法引用也就顺势出现。我们的println()语句不是早就已经有实现的方法了吗?好,我们就用println()语句的对象去调用,即 PrintStream ps = System.out;
有了这个对象,就要用这个对象去调用其相应的方法,即用ps对象去调用它自己的println()方法。
语句产生 ps::println;
1.2.1 代码演示(对象::实例方法名)
//Supplier中的T get()
//Employee中的String getName()
@Test
public void test2(){
//创建一个employee对象(这个pojo是我自己写的一个员工对象)
//1001是ID
//Tom是名字
//23年龄
//5600是薪水
Employee emp = new Employee(1001,"Tom",23,5600);
//Lambda表达式使用
Supplier sup1 = () -> emp.getName();
System.out.println(sup1.get());
System.out.print1n("**************");
//方法引用的使用
Supplier sup2 = emp::getName;
System.out.println(sup2.get());
}
1.2.2 代码解读
在使用了Lambda表达式的代码中我们发现,Supplier这个类的一个无参方法要执行 emp.getName(),但是我们发现,这个方法在emp这个对象本身内部就已经被实现了。由前面的定义可知,当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用。因此,我们就可以用相应的对象去调用其对应的方法,以此替换Supplier方法。
语句产生 emp::getName;
2. 类::静态方法名
2.1.1 代码演示
//情况二: 类::静态方法
//Comparator中的 int compare(T t1,T t2)
//Integer中的 int compare(T t1,T t2)
@Test
public void test3(){
//使用lambda表达式的写法
Comparator com1 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
System.out.printn"(*****************");
//使用方法引用之后的写法
Comparator com2 = Integer::compare;
System.out.print1n(com2.compare(12,3));
}
2.1.2 代码解读
在上述的代码中,我们可以看到Comparator将要执行一个带双参的方法,这个方法要做的事就是执行Integer.compare(t1,t2);可是我们发现,这个传递给Lambda体的操作,已经有实现的方法了,那就是Integer这个类中的compare方法,所以可以使用方法引用。
语法产生 Integer::compare;
2.2.1 代码演示
//Function中的 R apply(T t)
//Math中的 Long round(Double d)
@Test
public void test4() {
//lambda表达式
Function func1 = d -> Math.round(d);
System.out.print1n(func1.apply(12.3));
System.out.print1n("************");
//方法引用
Function func2 = Math::round;
System.out.println(func2.apply(12.6));
}
2.2.2 代码解读
在上述的代码中,我们可以看到Function将要执行一个带参的方法,这个方法要做的事就是执行Math.round();可是我们发现,这个传递给Lambda体的操作,已经有实现的方法了,那就是Math这个类中的round方法,所以可以使用方法引用。
语法产生 Math::round;
3. 类::实例方法名
3.1.1 代码演示
//情况三:类::实例方法(有难度)
// Comparator中的int comapre(T t1,T t2)
// String中的int t1. compareTo(t2)
@Test
public void test5() {
//使用Lambda表达式演示
Comparator com1 = (s1,s2) -> s1.compareTo(s2);
System.out.print1n(com1.compare("abc","abd"));
System.out.println("***************");
//使用方法引用的演示
Comparator com2 = String::compareTo;
System.out.println(com2.compare("abd","abm"));
}
3.1.2 代码解读
在上述的代码中,我们可以看到Comparator将要执行一个带双参的方法,这个方法要做的事就是执行s1.compareTo(s2);可是我们发现,这个传递给Lambda体的操作,已经有实现的方法了,那就是String这个类中的compareTo方法,所以可以使用方法引用。
语法产生 String::compareTo;
3.2.1 代码演示
//BiPredicate中的 boolean test(T t1, T t2);
//String中的 boolean t1.equals(t2)
@Test
pub1ic void test6() {
//使用Lambda表达式
BiPredicate pre1 = (s1,s2) -> s1.equals(s2);
System.out.print1n(pre1.test("abc","abc"));
System.out.println("***************");
//使用方法引用
BiPredicate pre2 = String::equals;
System.out.println(pre2.test("abc","abc"));
}
3.2.2 代码解读
在上述的代码中,我们可以看到BiPredicate将要执行一个带双参的方法,这个方法要做的事就是执行s1.equals(s2);可是我们发现,这个传递给Lambda体的操作,已经有实现的方法了,那就是String这个类中的equals方法,所以可以使用方法引用。
语法产生 String::equals;
@Test
public void test() {
//创建一个employee对象(这个pojo是我自己写的一个员工对象)
//1001是ID
//Jerry是名字
//23年龄
//6000是薪水
Employee employee = new Employee(1001,"Jerry",23,6000);
//使用Lambda表达式
Function func1 = e -> e.getName();
System.out.println(func1.apply(employee));
System.out.println("***************");
//使用方法引用
Function func2 = Employee::getName;
System.out.println(func2.apply(employee));
}
4. 构造器引用
4.1 代码演示
//构造器引用
//Supplier中的 T get()
//Employee的空参构造器: Employee()
@Test
pub1ic void test1(){
//正常写法
Supplier sup = new Supplier() {
@override
public Employee get() {
return new Emp1oyee();
}
};
//使用lambda表达式的写法
Supplier sup1 = () -> new Employee();
//使用构造器引用的写法
Supplier sup2 = Employee::new;
}
4.2 代码演示
//Function中的 R apply(T t)
//Employee的带参构造器: Employee(int id)
@Test
public void test2(){
//使用lambda表达式的写法
Function func1 = id -> new Employee(id);
Employee employee = func1.apply(1001);
System.out.print1n(employee);
//使用构造器引用的写法
Function func2 = Employee::new;
Employee employee1 = func2.apply(1002);
System.out.print1n(emp1oyee1);
}
4.3 代码演示
//BiFunction中的 R apply(T t,U u)
//Employee的带双参构造器: Employee(int id,String name)
@Test
public void test(){
//使用lambda表达式的写法
BiFunction func1 = (id,name) -> new Employee(id,name)
System.out.print1n(func1.app1y(1001,"Tom"));
//使用构造器引用的写法
BiFunction func2 = Employee::new;
System.out.print1n(func2.app1y(1002,"Tom"));
}
5. 数组引用
5.1 代码演示
//数组引用
//如果将数组看作一个特殊的类,那就和构造器引用的使用没有什么区别
//Function中的R apply(T t)
@Test
public void telt4(){
//使用lambda表达式的写法
Function func1 = length -> new String[length];
String[] arr1 = func1.apply(5);
System.out.println(Arrays.toString(arr1));
//使用构造器引用的写法
Function func2 = String[]::new;
String[] arr2 = func2.apply(10);
System.out.println(Arrays.tostring(arr2));
}