JDK8新特性之方法引用与构造器引用快速入门

目录

一、方法引用

方法引用的写法可以理解为Lambda表达式的另外一种表现形式。

不熟悉Lambda表达式的可以参考JDK8新特性之Lambda表达式快速入门

方法引用的语法

使用操作符 "::" 将方法名和对象或类的名字分隔开来。语法有3种:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法

使用时需满足的2个条件

条件一:若 Lambda 方法体中的功能,已经有方法提供了实现,可以使用方法引用。

条件二:方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致

通过示例快速入门

对象::实例方法

通过示例来理解使用时需满足的条件一

java 复制代码
System.out.println(str);
//拆开写为
PrintStream ps = System.out;
ps.println(str);

上面这段代码的ps为PrintStream对象实例,println()是其已经实现好的方法。符合使用时需满足的条件一

java 复制代码
Consumer<String> con = (str) -> System.out.println(str);
con.accept("Hello World!");
// 方法引用的写法
Consumer<String> con2 = System.out::println;
con2.accept("Hello JDK8!");

怎么理解使用时需满足的条件二,看源码:

java 复制代码
@FunctionalInterface
public interface Consumer<T> {
    
    void accept(T t);
    //......
}

上面示例中,Consumer的泛型是String类型,那么接口方法可以理解为"void accept(String t)",再看看System.out.println()的源码:

java 复制代码
public class PrintStream extends FilterOutputStream implements Appendable, Closeable {
    
    public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

println()方法也是一个String类型的入参,也是void返回类型,跟Consumer的accept()方法一样。这就符合使用时需满足的条件二

再看一个方法引用的示例,以加深印象:

java 复制代码
@Test
public void test2(){
	Employee emp = new Employee(101, "张三", 18, 9999.99);

	Supplier<String> sup = () -> emp.getName();
	System.out.println(sup.get());
	
	Supplier<String> sup2 = emp::getName;
	System.out.println(sup2.get());
}

getName()方法是Employee类里已经实现好的方法,满足条件一。

getName()方法没有入参,会返回String类型,跟Supplier的方法一致,所以满足条件二。

类::静态方法

代码示例:

我们常用的Comparator类的compare()方法,有2个入参,会返回一个int类型。

java 复制代码
@FunctionalInterface
public interface Comparator<T> {
	
	int compare(T o1, T o2);
	//......
}

跟Integer类已提供好的静态方法compare()入参返回值一致。

java 复制代码
public final class Integer extends Number implements Comparable<Integer> {

	public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    //......
}

那么就满足2个使用条件,Lambda表达式就可以写成Integer::compare了。示例:

java 复制代码
@Test
public void test1(){
	Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
	//静态方法引用
	Comparator<Integer> com2 = Integer::compare;
}

再看一个静态方法引用的示例,以加深印象:

java 复制代码
@Test
public void test2(){
	BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
	System.out.println(fun.apply(1.5, 22.2));
		
	BiFunction<Double, Double, Double> fun2 = Math::max;
	System.out.println(fun2.apply(1.2, 1.5));
}

类::实例方法

这种是特殊用法。需要满足条件:参数列表的第一个参数,是方法的调用者,第二个参数是方法的参数(或者没有第二个参数)时。

结合示例理解,示例一:

java 复制代码
@Test
public void test1(){
	BiPredicate<String, String> bp = (x, y) -> x.equals(y);
	System.out.println(bp.test("abcde", "abcde"));
	
	BiPredicate<String, String> bp2 = String::equals;
	System.out.println(bp2.test("abc", "abc"));
}

Lambda表达式有2个入参x、y,x是equals()方法的调用者,第二个参数y是equals()方法的参数。满足使用条件。

结合示例理解,示例二:

java 复制代码
@Test
public void test2(){	
	Function<Employee, String> fun = (e) -> e.getName();
	System.out.println(fun.apply(new Employee()));
	
	Function<Employee, String> fun2 = Employee::getName;
	System.out.println(fun2.apply(new Employee()));
}

Lambda表达式有1个入参e,e是getName()方法的调用者,Lambda表达式没有第2个入参,且getName()方法也没有入参。满足使用条件。

二、构造器引用

类名::new

构造器的参数列表,需要与函数式接口中参数列表保持一致。

通过示例理解:

java 复制代码
public class Employee {

	private int id;
	private String name;
	private int age;
	private double salary;

	public Employee() {
	}

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

	public Employee(String name, int age) {
		this.name = name;
		this.age = age;
	}
	//...

通过构造器引用实例化:

java 复制代码
@Test
public void test(){
	//无参构造器
//	Supplier<Employee> fun1 = () -> new Employee();
	Supplier<Employee> fun1 = Employee::new;
	Employee emp1 = fun1.get();
	System.out.println(emp1);

	//一个入参的构造器
//	Function<String, Employee> fun2 = (name) -> new Employee(name);
	Function<String, Employee> fun2 = Employee::new;
	Employee emp2 = fun2.apply("张三");
	System.out.println(emp2);

	//二个入参的构造器
//	BiFunction<String, Integer, Employee> fun3 = (name, age) -> new Employee(name, age);
	BiFunction<String, Integer, Employee> fun3 = Employee::new;
	Employee emp3 = fun3.apply("张三", 18);
	System.out.println(emp3);
}

三、数组引用

类型[]::new

通过示例理解:

java 复制代码
@Test
public void test(){
//	Function<Integer, String[]> fun = (length) -> new String[length];
	Function<Integer, String[]> fun = String[]::new;
	String[] strArr = fun.apply(10);
	System.out.println(strArr.length);
	
//	Function<Integer, Employee[]> fun2 = (length) -> new Employee[length];
	Function<Integer, Employee[]> fun2 = Employee[]::new;
	Employee[] empArr = fun2.apply(10);
	System.out.println(empArr.length);
}

至此,本章结束。

相关推荐
num_killer4 小时前
小白的Langchain学习
java·python·学习·langchain
期待のcode4 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐4 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲5 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红5 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥5 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
小楼v5 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地5 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209255 小时前
Guava Cache 原理与实战
java·后端·spring
yangminlei5 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot