方法引用

1、什么是方法引用

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式,是lambda表达式的一种简写形式。 如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。方法引用通过方法的名字来指向一个方法。这样可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用 “::” 操作符将方法名和对象或类的名字分隔开来。

以下是四种使用情况:

  1. 特定类的任意对象的方法引用:类::实例方法
  2. 静态方法引用:类::静态方法
  3. 特定对象的方法引用:对象::实例方法
  4. 构造器引用:类::new

使用条件:

  1. 如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
  2. 方法的参数个数类型和返回值类型和接口中的方法一致

2、如何使用方法引用

 需要用到的一个JavaBean:Employee类

package FuncReference;

import java.util.Objects;

/*
 * wgy 2019/8/17 9:49
 */
public class Employee {
    private String name;
    private int age;
    private double salary;
    private String gender;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee(String name, int age, double salary, String gender) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.gender = gender;
    }

    public Employee() {

    }
    //省略getter和setter
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", gender='" + gender + '\'' +
                '}';
    }

}

(1)特定对象的方法引用

package FuncReference;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class StuFuncReference {
    public static void main(String[] args) {
        //引用System.out对象的println()方法
        //Lambda表达式的常规写法
        Consumer<String> consumer= s-> System.out.println(s);
        consumer.accept("Hello,World");
        //使用方法引用
        Consumer<String> consumer2=System.out::println;
        consumer2.accept("Hello,world");
        //内部类
        Employee shaobo=new Employee("suxing", 20, 30000);
        Supplier<String> supplier3 = new Supplier<String>() {
            @Override
            public String get() {
                return shaobo.getName();
            }
        };
        //Lambda表达式
        Supplier<String> supplier=()->shaobo.getName();
        //方法引用
        Supplier<String> supplier2=shaobo::getName;
    }

}

(2)类的静态方法引用

//引用Comparator类的compare方法
//常规Lambda表达式写法
Comparator<Integer> comparator1 = (o1,o2)->Integer.compare(o1,o2);
System.out.println(comparator1.compare(1,4));
//方法引用
Comparator<Integer> comparator2 = Integer::compare;
System.out.println(comparator2.compare(4,2));

(3)特定类的任意对象的方法引用

package FuncReference;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class StuFuncReference {
    public static void main(String[] args) {
   
        //引用类的任意对象的实例方法
        //常规Lambda表达式写法
        BiPredicate<String,String> biPredicate1=(x, y)->x.equals(y);
        System.out.println(biPredicate1.test("suxing","suxing"));

        //方法引用
        BiPredicate<String,String> biPredicate2=String::equals;
        System.out.println(biPredicate2.test("suixng","Suxing"));

        Employee suxing=new Employee("suxing", 20, 30000);
        //Lambda
        Function<Employee,String> function= employee->employee.getName();
        String name1 = function.apply(suxing);
        System.out.println(name1);

        //方法引用
        Function<Employee,String> function2=Employee::getName;
        String name2 = function2.apply(suxing);
        System.out.println(name2);
    }

}

BiPredicate 这是一个功能接口,因此可以用作lambda表达式或方法引用的赋值目标。源码:

@FunctionalInterface
public interface BiPredicate<T, U> {

    boolean test(T t, U u);
    //省略其他静态和默认方法
}

(4)构造器引用

package FuncReference;

import java.util.function.Supplier;

public class Test_new {
    public static void main(String[] args) {
        //无参构造方法引用
        //Lambda表达式
        Supplier<Employee> supplier1=()->new Employee();
        Employee employee1 = supplier1.get();
        System.out.println(employee1.toString());
        //方法引用
        Supplier<Employee> supplier2=Employee::new;
        Employee employee2 = supplier2.get();
        System.out.println(employee2.toString());
    }
}

从上述代码中可以看出,我们引用的都是无参构造方法,那么如何引用有参构造方法呢?

我们为了更直观的找到问题,把方法应用改回匿名内部类,如下:

//匿名内部类
Supplier supplier = new Supplier() {
    @Override
    public Object get() {
        return new Employee();
    }
};

如果我们想在匿名内部类中调用有参构造方法,我们可以自定义一个类似于Supplier的函数式接口MySupplier,并在该自定义接口的方法中传入要调用的构造的参数,如下:

package FuncReference;

@FunctionalInterface
public interface MySupplier<T>{
    T get(String name, int age, double salary);
}

然后,我们就可以像使用Supplier接口那样,使用我们自定义的MySupplier接口,结合方法引用,调用类的有参构造方法了,如下:

package FuncReference;

public class TestMySupplier {
    public static void main(String[] args) {
        MySupplier<Employee> mySupplier = Employee::new;
        Employee employee = mySupplier.get("suxing",22,5000);
        String name = employee.getName();
        System.out.println(name);
    }
}

方法引用但这里基本就介绍完了, Java 8 中有两大重要新特性,第一种Lambda 表达式我们在之前的文章中已经介绍过了,接下来的文章会详细介绍另外一种——Stream API。