Java方法的引用(打造Lambda表达式的升级版)

1.初入方法引用
2.通过对象名引用成员方法
3.通过类名引用静态方法
4.通过super引用成员方法
5.通过this引用成员方法
6.类的构造器引用
7.数组的构造方法的引用
在这里插入图片描述

1.初入方法引用

1.冗余的Lambda表达式解决方案:
例子:

   package untl1;

public class MyPrint {
    public static void print(printable pri)
    {
        pri.print("helloworld");
    }
    public static void main(String[] args) {
        print((str)->{
            System.out.println(str);
        });
    }
}
@FunctionalInterface
interface printable{
    void print(String str);
}
运行结果:
helloworld

如果不懂Lambda可以参照这一篇博客:Lambda表达式详解
分析上边的代码;

其中 prin 方法只管调用 printable 接口的 print 方法,而并不管 print 方法的具体实现逻辑会将字符串 打印到什么地方去。而 main 方法通过Lambda表达式指定了函数式接口 Printable 的具体操作方案为:拿到 String(类型可推导,所以可省略)数据后,在控制台中输出它。这段代码的问题在于,对字符串进行控制台打印输出的操作方案,明明已经有了现成的实现,那就是 System.out 对象中的 println(String) 方法。既然Lambda希望做的事情就是调用 println(String) 方法,那何必自己手动调 用呢

啥意思呢看用方法引用的例子:

package untl1;
public class MyPrint {
    public static void print(printable pri)
    {
        pri.print("helloworld");
    }
    public static void main(String[] args) {
        print(System.out::println);
    }
}
@FunctionalInterface
interface printable{
    void print(String str);
}
运行结果:
helloworld

卧槽,这么高级
下面是对上边代码的解释:

1.请注意其中的双冒号::写法,这被称为“方法引用”,而双冒号是一种新的语法,双冒号 :: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方 法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者
2.例如上例中, System.out 对象中有一个重载的 println(String) 方法恰好就是我们所需要的。那么对于 printString 方法的函数式接口参数,对于上边的两种写法是等效的

对于例子中两种写法的对比:

写法类型 格式 语义
Lambda表达式 s -> System.out.println(s); 拿到参数之后经Lambda之手,继而传递给 System.out.println 方法去处理。
方法引用 System.out::println 直接让 System.out 中的 println 方法来取代Lambda。两种写法的执行效果完全一 样,而第二种方法引用的写法复用了已有方案,更加简洁。 注:Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常

如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式——它们都 将被自动推导。而如果使用方法引用,也是同样可以根据上下文进行推导。 函数式接口是Lambda的基础,而方法引用是Lambda的孪生兄弟

上述的第二个例子就是把已经存在的System.out这个对象通过已经存在的printfln这个方法
再细品这句话:如果Lambda要表达的函数方案已经存在于某个方 法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者

2.通过对象名引用成员方法

其实和上边的例子差不多再来一个例子:

   package untl1;
public class MyPrint {
   public void printString(String str)
   {
       System.out.println(str.toUpperCase());
   }
   public  static  void prin(printable pri)
   {
       pri.print("helloworld");
   }

    public static void main(String[] args) {
        MyPrint p=new MyPrint();
        prin(p::printString);
    }

}
@FunctionalInterface
interface printable{
    void print(String str);
}
运行结果:
HELLOWORLD

你品你细品:如果Lambda要表达的函数方案已经存在于某个方 法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者

3.通过类名引用静态方法

我们分别用Lambda表达式和方法引用来举例对比,求一个数的绝对值,然和再输出

用Lambda表达式:

  package untl1;
public class MyPrint {
    public static void aaa(int num,printabs pri)
    {
        System.out.println(pri.aboutabs(num));
    }
    public static void main(String[] args) {
        aaa(-100,num->Math.abs(num));
    }
}
@FunctionalInterface
interface printabs{
    int  aboutabs(int  a);
}
输出结果:
100

用方法的引用:

package untl1;
public class MyPrint {
    public static void aaa(int num,printabs pri)
    {
        System.out.println(pri.aboutabs(num));
    }
    public static void main(String[] args) {
        aaa(-100,Math::abs);
    }
}
@FunctionalInterface
interface printabs{
    int  aboutabs(int  a);
}
输出结果:
100

4.通过super引用成员方法

如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。

废话不多说,先用Lambda举例子:

package untl1;
public class MyPrint extends human{
    public void sayhello()
    {
        System.out.println("hello我是human的儿子");
    }
    public void method(Greetable g)
    {
        g.greet();
    }
    public void show()
    {
        method(()->{
            human h=new human();
            h.sayhello();
        });
    }
    public static void main(String[] args) {
        MyPrint p=new MyPrint();
       p.show();
    }
}
 class human{
    public void sayhello()
    {
        System.out.println("hello,我是human");
    }
}
@FunctionalInterface
interface Greetable{
    void greet();
}
运行结果:
hello,我是human

那么上边的代码用方法的引用:

package untl1;
public class MyPrint extends human{
    public void sayhello()
    {
        System.out.println("hello我是human的儿子");
    }
    public void method(Greetable g)
    {
        g.greet();
    }
    public void show()
    {
        method(super::sayhello);
    }
    public static void main(String[] args) {
        MyPrint p=new MyPrint();
       p.show();
    }
}
 class human{
    public void sayhello()
    {
        System.out.println("hello,我是human");
    }
}
@FunctionalInterface
interface Greetable{
    void greet();
}
运行结果:
hello,我是human

其实和对象引用方法名一样的

5.通过this引用成员方法

this代表当前对象,如果需要引用的方法就是当前类中的成员方法,那么可以使用“this::成员方法”的格式来使用方法

package untl1;
public class MyPrint extends human{
    public void sayhello()
    {
        System.out.println("hello我是human的儿子");
    }
    public void method(Greetable g)
    {
        g.greet();
    }
    public void show()
    {
        method(this::sayhello);
    }
    public static void main(String[] args) {
        MyPrint p=new MyPrint();
       p.show();
    }
}
 class human{
    public void sayhello()
    {
        System.out.println("hello,我是human");
    }
}
@FunctionalInterface
interface Greetable{
    void greet();
}
输出结果:
hello我是human的儿子

6.类的构造器的引用

由于构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示

例子(Lambda表达式):

package untl1;
public class Person {
    private String name;
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static void printname(String name,PersonBuilder per)
    {
        System.out.println(per.buildPerson(name).getName());
    }

    public static void main(String[] args) {
        printname("哈哈",name->new Person(name));

    }
}
interface PersonBuilder {
    Person buildPerson(String name);
}
运行结果:
哈哈

用类构造器的引用:

package untl1;
public class Person {
    private String name;
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static void printname(String name,PersonBuilder per)
    {
        System.out.println(per.buildPerson(name).getName());
    }

    public static void main(String[] args) {
        printname("哈哈",Person::new);

    }
}
interface PersonBuilder {
    Person buildPerson(String name);
}
运行结果:
哈哈

7.数组的构造器引用

数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同

例子:

package untl1;
public class Person {
    public static int[] createArray(int length,ArrayBuild ab)
    {
        return ab.builderArray(length);
    }
    public static void main(String[] args) {
       // int arr[]=createArray(10,len->new int[len]);
        int arr[]=createArray(10,int[]::new);
        System.out.println(arr.length);
    }
}
interface ArrayBuild{
    int [] builderArray(int length);
}
运行结果:
10

猜你喜欢

转载自blog.csdn.net/qq_45737068/article/details/105802696
今日推荐