1.1 目标


了解Lambda的冗余场景
掌握方法引用的格式
了解常见的方法引用方式


1.2 Lambda的冗余场景


使用Lambda表达式求一个数组的和

  1. package com.itheima.demo04methodref;
  2. import java.util.function.Consumer;
  3. public class Demo01MethodRefIntro {
  4. // 求一个数组的和
  5. public static void getMax(int[] arr) {
  6. int sum = 0;
  7. for (int n : arr) {
  8. sum += n;
  9. }
  10. System.out.println(sum);
  11. }
  12. public static void main(String[] args) {
  13. // 使用Lambda表达式求一个数组的和
  14. printMax((int[] arr) -> {
  15. getMax(arr);
  16. });
  17. // 使用方法引用
  18. // 让这个指定的方法去重写接口的抽象方法,到时候调用接口的抽象方法就是调用传递过去的这个方法
  19. printMax(Demo01MethodRefIntro::getMax);
  20. }
  21. public static void printMax(Consumer<int[]> consumer) {
  22. int[] arr = {11, 22, 33, 44, 55};
  23. consumer.accept(arr);
  24. }
  25. }

1.3 体验方法引用简化Lambda


如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:

image.png
请注意其中的双冒号 :: 写法,这被称为“方法引用”,是一种新的语法。


1.4 方法引用的格式


符号表示 : ::

符号说明 : 双冒号为方法引用运算符,而它所在的表达式被称为方法引用。
应用场景 : 如果Lambda所要实现的方案 , 已经有其他方法存在相同方案,那么则可以使用方法引用。


1.5 常见引用方式


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

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

1.6 小结


首先了解Lambda表达式的冗余情况,体验了方法引用,了解常见的方法引用方式


1.7 对象名::引用成员方法


这是最常见的一种用法,与上例相同。如果一个类中已经存在了一个成员方法,则可以通过对象名引用成员方法,代 码为:
image.png

// 对象::实例方法
    @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);

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

        // Supplier<Long> su4 = now::setDate;
        // su4.get();
    }

方法引用的注意事项

1. 被引用的方法,参数要和接口中抽象方法的参数一样
2. 当接口抽象方法有返回值时,被引用的方法也必须有返回值


1.8 类名::引用静态方法
由于在 java.lang.System 类中已经存在了静态方法 currentTimeMillis ,所以当我们需要通过Lambda来调用该 方法时,可以使用方法引用 , 写法是:
image.png

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

    Supplier<Long> su = System::currentTimeMillis;

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

1.9 类名::引用实例方法


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


image.png

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

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

    int length = f1.apply("hello");
    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);
    System.out.println("str2 = " + str2); // loworld
}

1.10 类名::new引用构造器


由于构造器的名称与类名完全一样。所以构造器引用使用 类名称::new 的格式表示。首先是一个简单的 Person 类:
image.png
要使用这个函数式接口,可以通过方法引用传递:

image.png

// 类名::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);
}

1.11 小结


方法引用是对Lambda表达式符合特定情况下的一种缩写,它使得我们的Lambda表达式更加的精简,也可以理解为 Lambda表达式的缩写形式 , 不过要注意的是方法引用只能”引用”已经存在的方法

package com.itheima.demo04methodref;

import org.junit.Test;

import java.util.Arrays;
import java.util.Date;
import java.util.function.*;

/*
方法引用的注意事项:
    1.被引用的方法,参数要和接口中抽象方法的参数一样
    2.当接口抽象方法有返回值时,被引用的方法也必须有返回值
 */
public class Demo02 {
    // 类型[]::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));
    }


    // 类名::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);
    }


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

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

        int length = f1.apply("hello");
        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);
        System.out.println("str2 = " + str2); // loworld
    }

    // 类名::静态方法
    @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 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);

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

        // Supplier<Long> su4 = now::setDate;
        // su4.get();
    }


}