主题6:方法引用

    所谓方法引用,就是将已有的方法,作为lambda表达式的函数体进行调用,并返回执行结果。方法引用是特定场景的lambda表达式的简化。

语法:

    类名::方法名称

class Person {
   private final String name;
   private final int age;
   public int getAge() { return age; }
   public String getName() {return name; }
   ...
}
Person[] people = ...
Comparator<Person> byName = Comparator.comparing(p -> p.getName());
Arrays.sort(people, byName);

等价于:

Comparator<Person> byName = Comparator.comparing(Person::getName);

    可以说方法引用是lambda的一种语法糖,简化了lambda表达式;就是函数体为一个表达式的lambda表达式; 而且方法引用的语义也更加明确,指明了调用特定的方法。

参数传递:

因为函数式接口的方法参数对应于隐式方法调用时的参数,所以被引用方法签名可以通过放宽类型,装箱以及组织到参数数组中的方式对其参数进行操作,就像在调用实际方法一样:

Consumer<Integer> b1 = System::exit; // void exit(int status)

Consumer<String[]> b2 = Arrays:sort; // void sort(Object[] a)

Consumer<String> b3 = MyProgram::main; // void main(String... args)

Runnable r = Myprogram::mapToInt // void main(String... args)

方法引用的种类:

类方法引用:

    主要是引用成员方法、静态方法:

ClassName::methodName

引用普通成员方法:

    因为调用成员方法必须基于某个对象,对比到lambda,实际上就是 :

(ClassName obj, [参数列表] )->obj.methodName( [参数列表] )

    所以要求目标函数必须的参数数目是引用函数参数数目加1,第一个参数是方法的调用者;从第二个开始的参数个数要和需要调用方法的入参个数一致即可;

clipboard

   为了增强函数式接口的通用性,通常将其设计成泛型类型,以便可以引用不同类型的成员函数;

public interface  TestInterface2<T> {
     void test(T t, String b);
}

public class TestC {

    public String aa(String a){
         System.out.println(a);
         System.out.println("你好..................");
         return "";
     }

    public void bb(){
         System.out.println("bbbbbbbbbbbbbbbbb");
     }
     public static void main(String[] args) {
         TestInterface2<TestC> ti = TestC::aa;
         ti.test(new TestC(), "11111111111111");
         List<TestC> lts = new ArrayList<>();
         lts.add(new TestC());
         lts.forEach(TestC::bb);
     }
}

clipboard

引用静态成员方法:

因为静态成员方法不需要实例对象就可以调用,所以就相当于lambda:

( [参数列表] )->ClassName.methodName( [参数列表] )

    目标函数的参数与引用函数参数列表相同;

clipboard

public interface TestInterface3<T> {
     void test(T t);
}

public class TestD {

    public static void aa(String a){
         System.out.println(a);
         System.out.println("你好..................");
     }

    public static void main(String[] args) {
         TestInterface3<String> ti = TestD::aa;
         ti.test("asaaaa");
     }
}

clipboard

引用泛型方法:

如果要引用的方法是泛型方法:

(1)可以在符号 ::之后指定实际类型:

ClassName::<T>methodName

(2)也可以不显式指定泛型类型,编译器可以通过相关参数推导得到泛型类型,这样就和普通的方法引用风格一致了。

public class Person {
     String name;

    int age;

    public Person(String name, int age) {
         this.name = name;
         this.age = age;
     }

    public Person() {
     }
}

public interface MyFun<T> {

    int func(List<T> list, T r);
}

public class ListOpt {

    public static <T> int queryByAge(List<T> ts, T r){
         int i = 0;
         for (T t: ts) {
             if(t == r){
                 i++;
             }
         }
         return i;
     }
}

public class Demo {
     public static <T> void callFun(MyFun<T> myfun, List<T> arr, T v){
         int i = myfun.func(arr, v);
         System.out.println("结果:" + i);
     }

    public static void main(String[] args) {
         List<Person> pl = new ArrayList<>();
         pl.add(new Person("李四", 21));
         Person p = new Person("aaa", 22);
         pl.add(p);
         pl.add(p);
         pl.add(p);
         Demo.callFun(ListOpt::<Person>queryByAge, pl, p);
         Demo.callFun(ListOpt::queryByAge, pl, new Person());
     }
}

clipboard

实例方法引用:

  引用对象的成员函数

instanceName::methodName

   引用实例方法,如果方法修改了实例自身的状态,则通过函数式接口调用目标函数时,也会修改实例的状态,实际上就是在lambda中引用了外部变量

public class TestBN {
     public TestBN() {
         System.out.println("创建TestBN实例.............");
     }

    private int i = 10;
     public void testAtr(){
         System.out.println(i);
         i *= i;
     }

    public static void main(String[] args) {
         TestBN o = new TestBN();
         TestInterface t2 = o::testAtr;
         t2.test();  //10
         o.testAtr();    // 100
         t2.test();  //1000
     }
}

引用父类方法:

super::methodName

public Runnable superTS(){
     return super::toString;
}

构造函数引用:

    引用某个类型的构造函数来创建对象:

ClassName::new

public class TestBN {
     public TestBN() {
         System.out.println("创建TestBN实例.............");
     }

    public static void main(String[] args) {
         TestInterface ti = TestBN::new;
         Object o = ti.test();
         System.out.println(o);
     }
}

数组构造函数引用:

type[]::new

public interface ArrayInitFun<T> {
     T create(int i);
}

public class Demo {

public static void main(String[] args) {

ArrayInitFun<int[]> aif = int[]::new;

int[] i = aif.create(5); //等于 new int[10];

System.out.println(i);

}

}

猜你喜欢

转载自www.cnblogs.com/zyj-468161691/p/12214005.html