【jdk8新特性】方法引用

简介: 【jdk8新特性】方法引用

【jdk8新特性】方法引用

什么是方法引用,为什么要用方法引用

什么是方法引用

方法引用是为了简化lambda表达式而出现的,表现形式是A::B

为什么要用方法引用

我们来看一个例子就可以理解为什么要用方法引用

// 求一个数组的和
    public static void getMax(int[] arr) {
        int sum = 0;
        for (int n : arr) {
            sum += n;
        }
        System.out.println(sum);
    }

    public static void main(String[] args) {
        // 使用Lambda表达式求一个数组的和
        /*printMax((int[] arr) -> {
            getMax(arr);
        });*/ // 例子一

        // 使用方法引用
        // 让这个指定的方法去重写接口的抽象方法,到时候调用接口的抽象方法就是调用传递过去的这个方法
        printMax(Demo01MethodRefIntro::getMax);// 例子二
    }

    public static void printMax(Consumer<int[]> consumer) {
        int[] arr = {11, 22, 33, 44, 55};
        consumer.accept(arr);
    }
}

我们可以看到我们有一个getMax方法进行数组求和运算,此时我们使用Lambda表达式来进行数组求和,可以看到第一个例子它用lambda调用了 getMax方法 但这样那我为什么不直接用getMax方法呢?所以我们有了例子二:利用类::方法名 来用作方法引用,即把方法名对应的方法 重写到accept方法。

常见引用方式

方法引用在JDK 8中使用方式相当灵活,有以下几种形式:

  1. instanceName::methodName 对象::方法名
  2. ClassName::staticMethodName 类名::静态方法
  3. ClassName::methodName 类名::普通方法
  4. ClassName::new 类名::new 调用的构造器
  5. TypeName[]::new String[]::new 调用数组的构造器

其中3:类名::普通方法,按传统语法的理解是错误的,这里进行了处理

对象名::引用成员方法

// 对象::实例方法
@Test
public void test01() {
    Date now = new Date();

    /*Supplier<Long> su1 = () -> {
            return now.getTime();
        };*/

    // 使用方法引用
    Supplier<Long> su1 = now::getTime;

    Long aLong = su1.get();
    System.out.println("aLong = " + aLong);
}

这里我们使用了Date类的实例对象 now进行方法引用

补充注意点

注意:方法引用有两个注意事项

 1.被引用的方法,参数要和接口中抽象方法的参数一样
 2.当接口抽象方法有返回值时,被引用的方法也必须有返回值
         Supplier<Long> su3 = now::setTime;// 错误
         su3.get();

​ Supplier su4 = now::setDate;
​ su4.get();

可以看出setTime与setDate都需要参数且不需要返回值,但get方法是由返回值不需要参数,因为本质是重写get方法,但现在参数、返回值 不匹配所有不能这样写。

类名::引用静态方法

// 类名::静态方法
@Test
public void test02() {
    /*Supplier<Long> su = () -> {
        return System.currentTimeMillis();
    };*/

    Supplier<Long> su = System::currentTimeMillis;

    Long time = su.get();
    System.out.println("time = " + time);
}

类名::引用实例方法

// 类名::实例方法
@Test
public void test03() {
    /*Function<String, Integer> f1 = (String str) -> {
        return str.length();
    };*/

    // 类名::实例方法(注意:类名::类名::实例方法实际上会将第一个参数作为方法的调用者)
    Function<String, Integer> f1 = String::length;

    int length = f1.apply("hello");// 调用的实际是"hello".length()
    System.out.println("length = " + length);

    // BiFunction<String, Integer, String> f2 = String::substring;
    // 相当于这样的Lambda
    BiFunction<String, Integer, String> f2 = (String str, Integer index) -> {
        return str.substring(index);
    };
    String str2 = f2.apply("helloworld", 3);// 相当于"helloworld".substring(3);
    System.out.println("str2 = " + str2); // loworld
}

Java面向对象中,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用者。

类名::new引用构造器

// 类名::new引用类的构造器
@Test
public void test04() {
    /*Supplier<Person> su1 = () -> {
        return new Person();
    };*/

    Supplier<Person> su1 = Person::new;

    Person person = su1.get();
    System.out.println("person = " + person);

    /*BiFunction<String, Integer, Person> bif = (String name, Integer age) -> {
        return new Person(name, age);
    };*/
    BiFunction<String, Integer, Person> bif = Person::new;
    Person p2 = bif.apply("凤姐", 18);
    System.out.println("p2 = " + p2);
}

Person类

public class Person {
    private String name;
    private int age;

    public Person() {
        System.out.println("执行无参构造");
    }

    public Person(String name, int age) {
        System.out.println("执行有参构造: " + name + ", " + age);
        this.name = name;
        this.age = age;
    }
}

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

数组::new 引用数组构造器

// 类型[]::new
@Test
public void test05() {
    /*Function<Integer, int[]> f1 = (Integer length) -> {
        return new int[length];
    };*/

    Function<Integer, int[]> f1 = int[]::new;

    int[] arr1 = f1.apply(10);
    System.out.println(Arrays.toString(arr1));
}

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

目录
相关文章
|
2月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
27 1
|
3月前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
46 3
|
2月前
|
存储 安全 Java
JDK1.8 新的特性
JDK1.8 新的特性
21 0
|
3月前
|
编解码 安全 Java
jdk8新特性-接口和日期处理
jdk8新特性-接口和日期处理
|
4月前
|
API
JDK8的stream有求和方法吗?
【8月更文挑战第20天】JDK8的stream有求和方法吗?
137 3
|
4月前
|
Java API
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
|
4月前
|
Java
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
|
4月前
|
Oracle Java 关系型数据库
JDK8到JDK29版本升级的新特性问题之未来JDK的升级是否会成为必然趋势,如何理解
JDK8到JDK29版本升级的新特性问题之未来JDK的升级是否会成为必然趋势,如何理解
|
4月前
|
Oracle 安全 Java
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
|
3月前
|
Java 编译器 API
JDK8新特性--lambda表达式
JDK8的Lambda表达式是Java语言的一大进步。它为Java程序提供了更多的编程方式,让代码更加简洁,也让函数式编程的概念在Java中得到了体现。Lambda表达式与Java 8的其他新特性,如Stream API、新的日期时间API一起,极大地提高了Java编程的效率和乐趣。随着时间的流逝,Java开发者对这些特性的理解和应用将会越来越深入,进一步推动Java语言和应用程序的发展。
15 0