// 理解
Function<Employee, String> fun1 = (emp) -> emp.getName();
Function<Employee, String> fun2 = Employee::getName;
Supplier<String> supplier2 = Employee::staticMethod;

Employee employee = new Employee();
Supplier<String> supplier1 = employee::getName;

// Lambda 尖括号右面的内容实际上是函数式接口方法的方法体和尖括号里面调用的方法不相关
// 方法调用 :: 的一条规则就是 :: 右面的方法也就是调用的方法要和函数式接口中的方法入参返回值一致

// Function<Employee, String> fun2 = Employee::getName; 是一种特殊的写法,Function 接口中的 R apply(T t)
// 方法体中的语句只有一句且是对 T 的一个方法的引用。上面的也就是我想要调用 Employee 对象的 getName() 方法。

一、方法引用:

若 Lambda 体总的内容有方法已经实现了,我们可以使用 “方法引用”(可以理解为方法引用时 Lambda 表达式的另外一种表现形式)

主要的三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名

要求:

1.类或对象的方法的参数列表和返回值必须和 Lambda 中函数接口方法的参数列表和返回值一致
2.如果 Lambda 参数列表中有两侧参数,第一个参数时实例方法的调用者,二第二个参数是实例方法的参数时,可以使用 ClassName::method 也就是 类::实例方法形式。

/**
 * 对象::实例方法名
 * 类::静态方法名
 * 类::实例方法名
 *
 * 注意:
 *  Lambda 体中调用的方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致
 */


// 对象:: 实例方法名
@Test
public void test1() {
//        Consumer<String>  con = (x) -> System.out.println(x);

    PrintStream ps = System.out;
    // 使用方法引用的时候必须 参数列表和返回类型一致
    // 这里 ps.println(s) 方法 void println(String x) 和 Consumer 的  void accept(T t); 一致
    Consumer<String> con1 = ps::println;

    Consumer<String> con2 = System.out::println;
    con2.accept("abcdef");
}

@Test
public void test2() {
    Employee emp = new Employee();
    Supplier<String> sup = () -> emp.getName();
    System.out.println(sup.get());

    Supplier<Integer> sup2 = emp::getAge;
    System.out.println(sup2.get());
}

// 类::静态方法名
public void test3() {
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

    Comparator<Integer> com2 = Integer::compare;
}

// 类::实例方法名
// 特殊,需要两个参数,第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用 ClassName::method
@Test
public void test5 () {
    BiPredicate<String, String> bp = (x, y) -> x.equals(y);

    BiPredicate<String, String> bp2 = String::equals;

}

@Test
public void test4 () {
    Function<Employee, String> fun = (emp) -> emp.getName();
    Function<Employee, String> fun2 = Employee::getName;
    // 这是一种简单写法,只有当入参是一个的时候可以简略,然后使用 类::实例方法 调用,
    // 注意这个只是上面的简略写法
}

理解

Function<Employee, String> fun1 = (emp) -> emp.getName();
Function<Employee, String> fun2 = Employee::getName;
Supplier<String> supplier2 = Employee::staticMethod;

Employee employee = new Employee();
Supplier<String> supplier1 = employee::getName;

Lambda 尖括号右面的内容实际上是函数式接口方法的方法体和尖括号里面调用的方法不相关
方法调用 :: 的一条规则就是 :: 右面的方法也就是调用的方法要和函数式接口中的方法入参返回值一致。

Function<Employee, String> fun2 = Employee::getName; 是一种特殊的写法,Function 接口中的 R apply(T t)

方法体中的语句只有一句且是对 T 的一个方法的引用。上面的也就是我想要调用 Employee 对象的 getName() 方法。

二、构造器引用

ClassName::new
注意:
需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
因为构造方法是默认的 static 方法,实际上就是 类::静态方法

// 构造器引用
@Test
public void  test5() {
    Supplier<Employee> sup = () -> new Employee();
    sup.get();

    // 构造器引用方法
    // 调用的是无参的构造方法,因为 Supplier 函数式接口的方法 get 是一个无参的返回是一个对象的方法
    Supplier<Employee> sup2 = Employee::new;
}

@Test
public void test6() {
    Function<String, Employee> fun = (str) -> new Employee(str);

    // 这里调用的是有一个参数的构造器,因为 Function 函数式接口里面的方法 apply
    // 是一个有一个参数返回是一个对象的方法
    Function<String, Employee> fun2 = Employee::new;
    System.out.println(fun2.apply("tom"));
}

三、数组引用

Type[]::new

// 数组引用
@Test
public void test7() {
    Function<Integer, String[]> fun = (x) -> new String[x];
    String[] strs = fun.apply(10);
    System.out.println(strs.length);

    Function<Integer, String[]> fun2 = String[]::new;
    System.out.println(fun2.apply(10).length);
}