【JDK1.8 新特性】方法引用,构造器引用

2023-03-08 11:17:19 浏览数 (2)

1. 前言

Lambda表达式是可以简化函数式接口的变量或形参赋值的语法。

而方法引用和构造器引用是为了简化Lambda表达式的。

2. 方法引用

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

2.1 方法引用语法格式

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

理解:类(或对象) :: 要调用的类(或对象)中的方法

2.2 方法引用使用前提

要求1:

  • 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参数匹配(类型相同或满足多态场景也可以) 注意: 此方法b是非静态方法,需要对象调用。但是形式上,写成对象a所属的类调用。

2.3方法引用的理解

  • 声明 接口<泛型> 引用 = 类 :: 类中的方法名接口<泛型> 引用 = 对象 :: 对象中的方法名
  • 调用 引用.重写的方法(实参);
代码语言:javascript复制
// 发一:以前的方法
Supplier<String> sup = new Supplier<String>(){
	@Override
	public String get(){// get()和getName()的参数和返回值类型都是同一个类型,就可以使用方法引用
		return emp.getName();
	}
}
sup.get();

/*******************************/

// 法二:方法引用
Supplier<String> sup = emp::getName;//调用抽象方法中的方法
sup.get();//调用重写的抽象方法get

也就是以 “::” 重写抽象方法中的方法,但是这里的方法调用没有括号,再通过引用来调用重写的抽象方法,形成链式调用,返回值类型由泛型参数决定。

从上面的方法可以看出,Lambda表达式使代码变得更加简洁,但是执行效率却变低了!! !

2.4 示例代码

代码语言:javascript复制
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));
	}

}

3. 构造器引用、数组引用

理解了方法引用,构造器引用、数组引用就很好理解了。

  • 构造器引用格式: 接口<泛型> 引用 = 类名 :: new ,调用的构造器由泛型参数决定。
  • 数组引用格式: 接口<泛型> 引用 = 数组名[] :: new,数组的初始化容量由泛型参数决定。

0 人点赞