Java8新特性--方法引用

一.什么是方法引用?

谈到方法引用,就必须提到Lambda,因为方法引用是用在Lambda表达式的,方法引用是一种更简洁易懂的Lambda表达式,和Lambda表达式一样,也是一种语法糖

当我们需要使用Lambda表达式来实现一个函数式接口的抽象方法时,已经有存在的类实现了我们需要的功能方法,这时我们完全没必要再造一个实现方法,可以直接用Lambda表达式调用这个方法来实现,虽然这样子实现可以,但是很冗余,此时使用方法引用就很简洁清晰,可读性更高。

​ 方法引用的运算符为::

​ 下面用一个例子解释下上面所说的:(方法引用的使用下面会再讲)

// 之前介绍的函数式接口中有个消费型接口Consumer,抽象方法accept接收一个参数,没有返回值
public static void main(String[] args) {
    Consumer<String> consumer = (s) -> System.out.println(s);
    consumer.accept("Hello Java");
}

​ 上面Consumer接口中的抽象方法accept实现的是打印传入的字符串,Lambda表达式中调用的是System.out.println,是System.out已经实现了的,所以在Lambda表达式中我就没有自己实现一个打印的方法,而是直接调用了已存在的方法,这里就可以使用方法引用来简化代码了,简化后如下所示:

public static void main(String[] args) {
    Consumer<String> consumer = System.out:println;
    consumer.accept("Hello Java");
}

重点:看了上面所说所演示,那为啥这样子的就可以用方法引用来简化呢?

  1. System.out是存在的对象
  2. println是已存在的方法
  3. 函数接口的方法accept的参数类型是String,并且无返回值,与方法引用的println参数类型一致。

所以,要能使用方法引用,必须满足:方法引用的对象或类是存在的或已知的,方法也是存在的,还需要方法参数列表保持一致。

二.方法引用的分类

总共有三种引用,引用方法,引用构造器,引用数组。有如下几种分类

1. 通过对象引用成员方法

举例:

public static void main(String[] args) {
    // 使用Lambda
    Consumer<String> consumer = (s) -> System.out.println(s);
    // 使用方法引用
    Consumer<String> consumer1 = System.out::println;
    
    consumer.accept("hello");
    consumer1.accept("hello");
}

解释:System.out是PrintStream类型的对象引用,println是一个成员方法,而Consumer是一个函数式接口,内部的抽象方法为accept,参数列表与println参数列呗一致,都是接收一个String类型参数,所以可以使用方法引用,这种就是对象引用成员方法。

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

举例:

public static void main(String[] args) {
    	// 使用Lambda
        Function<Integer, Integer> func = (i) -> Math.abs(i);
        Integer i = func.apply(-10);
        System.out.println(i);
    	// 使用方法引用
    	Function<Integer, Integer> func1 = Math::abs;
    	Integer i1 = func1.apply(-10);
    	System.out.println(i1);
    }

解释:Math是一个类,而abs是Math类的静态方法;Function接口中抽象方法apply参数列表与abs方法的参数列表是一致的,因此可以使用方法引用,这种就是通过类名引用静态方法。

3.类的构造器引用

由于构造器名字和类名一样,并不是固定的,所以构造器的引用使用格式:类名::new

举例:

class Person {
    private String name;

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

    public String getName() {
        return this.name;
    }
}

interface PersonBuilder {
    public abstract Person buildPerson(String name);
}

public class MethodReferenece {
    public static void main(String[] args) {
        // Lambda方式
        PersonBuilder pb = (name) -> new Person(name);
        System.out.println(pb.buildPerson("zhangsan").getName());

        // 方法引用
        PersonBuilder pb1 = Person::new;
        System.out.println(pb1.buildPerson("lisi").getName());
    }
}

解释:PersonBuilder接口的抽象方法是buildPerson是为了返回一个Person对象,那必须要new一个对象返回,new一个对象实质就是调用了构造方法,而且类Person存在,带参构造方法也存在,并且参数与函数式接口的抽象方法一样,都是String,所以可以使用方法引用,用类的构造器引用。

4. 数组的构造器引用

数组也是Object的子类对象,所以同样是具有构造器的,实质也是构造器的引用,但是语法格式有些不同,数组的构造器引用格式为:类型[]::new,其中这个类型可以是基本类型也可以是类。

举例:

interface ArrayBuilder {
    public abstract int[] buildArray(int length); 
}

public class MethodReferenece {
    public static void main(String[] args) {
        // Lambda方式
        ArrayBuilder ab = (len) -> new int[len];
        int[] array = ab.buildArray(5);
        for (int i = 0; i < array.length; i++) {
            array[i] = i;
        }
        for (int i: array) {
            System.out.println(i);
        }

        // 方法引用
        ArrayBuilder ab1 = int[]::new;
        int[] array1 = ab1.buildArray(5);
        for (int i = 0; i < array1.length; i++) {
            array1[i] = i * 2;
        }
        for (int i: array1) {
            System.out.println(i);
        }

    }
}

解释:这里演示了使用int[]数组的构造器引用,这里使用int[]::new时候,根据函数式接口ArrayBuilder的抽象函数buildArray的参数列表是一个整形,会自动调用的是new一个数组的时候带一个整形参数的构造方法,所以参数一致,也是可以使用方法引用的,这种就是数组的构造器引用。

三.总结

并不是所有的Lambda表达式都可以使用方法引用的,复杂的Lambda表达式还是得用Lambda表达式编写。

但使用方法引用会比较清晰简洁,能使用的地方还是推荐使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值