Java8新特性:方法引用与构造器引用

简介: Java8新特性:方法引用与构造器引用

我是南城余!阿里云开发者平台专家博士证书获得者!

欢迎关注我的博客!一同成长!

一名从事运维开发的worker,记录分享学习。

专注于AI,运维开发,windows Linux 系统领域的分享!

本章节对应知识库

https://www.yuque.com/nanchengcyu/java

本内容来自尚硅谷课程,此处在知识库做了个人理解

————————————————

Lambda表达式是可以简化函数式接口的变量或形参赋值的语法。而方法引用和构造器引用是为了简化Lambda表达式的。

4.1 方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

4.1.1 方法引用格式
  • 格式:使用方法引用操作符 “::” 将类(或对象) 与 方法名分隔开来。
  • 两个:中间不能有空格,而且必须英文状态下半角输入
  • 如下三种主要使用情况:
  • 情况1:对象 :: 实例方法名
  • 情况2:类 :: 静态方法名
  • 情况3:类 :: 实例方法名
4.1.2 方法引用使用前提

**要求1:**Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法来完成的

例如:System.out对象,调用println()方法来完成Lambda体

Math类,调用random()静态方法来完成Lambda体

要求2:

针对情况1:函数式接口中的抽象方法a在被重写时使用了某一个对象的方法b。如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同,则我们可以使用方法b实现对方法a的重写、替换。

针对情况2:函数式接口中的抽象方法a在被重写时使用了某一个类的静态方法b。如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同,则我们可以使用方法b实现对方法a的重写、替换。

针对情况3:函数式接口中的抽象方法a在被重写时使用了某一个对象的方法b。如果方法a的返回值类型与方法b的返回值类型相同,同时方法a的形参列表中有n个参数,方法b的形参列表有n-1个参数,且方法a的第1个参数作为方法b的调用者,且方法a的后n-1参数与方法b的n-1参数匹配(类型相同或满足多态场景也可以)

例如:t->System.out.println(t)

() -> Math.random() 都是无参

4.1.3 举例
public class MethodRefTest {
  // 情况一:对象 :: 实例方法
  //Consumer中的void accept(T t)
  //PrintStream中的void println(T t)
  @Test
  public void test1() {
    Consumer<String> con1 = str -> System.out.println(str);
    con1.accept("北京");
    System.out.println("*******************");
    PrintStream ps = System.out;
    Consumer<String> con2 = ps::println;
    con2.accept("beijing");
  }
  //Supplier中的T get()
  //Employee中的String getName()
  @Test
  public void test2() {
    Employee emp = new Employee(1001,"Tom",23,5600);
    Supplier<String> sup1 = () -> emp.getName();
    System.out.println(sup1.get());
    System.out.println("*******************");
    Supplier<String> sup2 = emp::getName;
    System.out.println(sup2.get());
  }
  // 情况二:类 :: 静态方法
  //Comparator中的int compare(T t1,T t2)
  //Integer中的int compare(T t1,T t2)
  @Test
  public void test3() {
    Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
    System.out.println(com1.compare(12,21));
    System.out.println("*******************");
    Comparator<Integer> com2 = Integer::compare;
    System.out.println(com2.compare(12,3));
  }
  //Function中的R apply(T t)
  //Math中的Long round(Double d)
  @Test
  public void test4() {
    Function<Double,Long> func = new Function<Double, Long>() {
      @Override
      public Long apply(Double d) {
        return Math.round(d);
      }
    };
    System.out.println("*******************");
    Function<Double,Long> func1 = d -> Math.round(d);
    System.out.println(func1.apply(12.3));
    System.out.println("*******************");
    Function<Double,Long> func2 = Math::round;
    System.out.println(func2.apply(12.6));
  }
  // 情况三:类 :: 实例方法  (有难度)
  // Comparator中的int comapre(T t1,T t2)
  // String中的int t1.compareTo(t2)
  @Test
  public void test5() {
    Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
    System.out.println(com1.compare("abc","abd"));
    System.out.println("*******************");
    Comparator<String> com2 = String :: compareTo;
    System.out.println(com2.compare("abd","abm"));
  }
  //BiPredicate中的boolean test(T t1, T t2);
  //String中的boolean t1.equals(t2)
  @Test
  public void test6() {
    BiPredicate<String,String> pre1 = (s1,s2) -> s1.equals(s2);
    System.out.println(pre1.test("abc","abc"));
    System.out.println("*******************");
    BiPredicate<String,String> pre2 = String :: equals;
    System.out.println(pre2.test("abc","abd"));
  }
  // Function中的R apply(T t)
  // Employee中的String getName();
  @Test
  public void test7() {
    Employee employee = new Employee(1001, "Jerry", 23, 6000);
    Function<Employee,String> func1 = e -> e.getName();
    System.out.println(func1.apply(employee));
    System.out.println("*******************");
    Function<Employee,String> func2 = Employee::getName;
    System.out.println(func2.apply(employee));
  }
}

4.2 构造器引用

当Lambda表达式是创建一个对象,并且满足Lambda表达式形参,正好是给创建这个对象的构造器的实参列表,就可以使用构造器引用。

格式:类名::new

举例:

public class ConstructorRefTest {
  //构造器引用
    //Supplier中的T get()
    //Employee的空参构造器:Employee()
    @Test
    public void test1(){
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");
        Supplier<Employee>  sup1 = () -> new Employee();
        System.out.println(sup1.get());
        System.out.println("*******************");
        Supplier<Employee>  sup2 = Employee :: new;
        System.out.println(sup2.get());
    }
  //Function中的R apply(T t)
    @Test
    public void test2(){
        Function<Integer,Employee> func1 = id -> new Employee(id);
        Employee employee = func1.apply(1001);
        System.out.println(employee);
        System.out.println("*******************");
        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);
    }
  //BiFunction中的R apply(T t,U u)
    @Test
    public void test3(){
        BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
        System.out.println(func1.apply(1001,"Tom"));
        System.out.println("*******************");
        BiFunction<Integer,String,Employee> func2 = Employee :: new;
        System.out.println(func2.apply(1002,"Tom"));
    }
}
package com.atguigu.java2;
/**
 * @author 尚硅谷-宋红康 邮箱:shkstart@126.com
 */
public class Employee {
  private int id;
  private String name;
  private int age;
  private double salary;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public double getSalary() {
    return salary;
  }
  public void setSalary(double salary) {
    this.salary = salary;
  }
  public Employee() {
    System.out.println("Employee().....");
  }
  public Employee(int id) {
    this.id = id;
    System.out.println("Employee(int id).....");
  }
  public Employee(int id, String name) {
    this.id = id;
    this.name = name;
  }
  public Employee(int id, String name, int age, double salary) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.salary = salary;
  }
  @Override
  public String toString() {
    return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
  }
}

4.3 数组构造引用

当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参,正好是给创建这个数组对象的长度,就可以数组构造引用。

格式:数组类型名::new

举例:

//数组引用
//Function中的R apply(T t)
@Test
public void test4(){
    Function<Integer,String[]> func1 = length -> new String[length];
    String[] arr1 = func1.apply(5);
    System.out.println(Arrays.toString(arr1));
    System.out.println("*******************");
    Function<Integer,String[]> func2 = String[] :: new;
    String[] arr2 = func2.apply(10);
    System.out.println(Arrays.toString(arr2));
}
目录
相关文章
|
4天前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
14 4
|
6天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
36 4
|
17天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
36 17
|
10天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
13 2
|
18天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
13 2
|
12天前
|
Java Spring
JAVA获取重定向地址URL的两种方法
【10月更文挑战第17天】本文介绍了两种在Java中获取HTTP响应头中的Location字段的方法:一种是使用HttpURLConnection,另一种是使用Spring的RestTemplate。通过设置连接超时和禁用自动重定向,确保请求按预期执行。此外,还提供了一个自定义的`NoRedirectSimpleClientHttpRequestFactory`类,用于禁用RestTemplate的自动重定向功能。
|
Java
JAVA方法的定义
JAVA方法的定义
81 0
|
5月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
40 1
|
6月前
|
存储 Java
Java数组与带参数方法:定义、调用及实践
Java数组与带参数方法:定义、调用及实践
68 1
|
6月前
|
存储 Java
Java中带返回值方法的定义与调用技术
Java中带返回值方法的定义与调用技术
89 1