4. Java8新特性:方法引用与构造器引用
Lambda表达式(可查看本章前1小节)是可以简化函数式接口的变量或形参赋值的语法。而方法引用和构造器引用是为了简化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 举例
package com.test;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* CLassName: MethodReferenTest
* Package: com.test
* Description: 方法引用的使用
* 1、使用情境:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
* 2、方法引用:本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。
* 所以方法引用,也是函数接口的实例。
*
* 3、使用格式: 类(或对象) :: 方法名
* 4、具体分为如下三种情况:
* 对象 :: 非静态方法
* 类 :: 静态方法
*
* 类 :: 非静态方法
* 5、使用要求:要求 接口中的抽象方法的形参列表和返回值类型
* 与 方法引用的方法的形参列表和返回值类型 相同!
*
* @Author: JOKER-wqc
* @Version: v1.0
*/
public class MethodReferenceTest {
/*
情况一: 对象::实例方法
Consumer中的void accept(T t)
PrintStream中的void println(T t)
*/
@Test
public void test(){
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("hello!");
System.out.println("********* 方法引用 *********");
Consumer<String> con2 = System.out :: println;
con2.accept("hello!");
}
//Supplier中的 T get()
//Person中的String getName()
@Test
public void test1(){
Person p = new Person("王",18);
Supplier<String> sup = ()-> p.getName();
System.out.println(sup.get());
System.out.println("********* 方法引用 *********");
Supplier<String> sup1 = p :: getName;
System.out.println(sup1.get());
}
/*
情况二: 类 :: 静态方法
Comparator中的int compare(T t1,T t2)
Integer中的int compare(T t1,T t2)
*/
@Test
public void test2(){
Comparator<Integer> comp = (i1,i2) -> Integer.compare(i1,i2);
System.out.println(comp.compare(12,45));
System.out.println("********* 方法引用 *********");
Comparator<Integer> comp1 = Integer :: compare;
System.out.println(comp1.compare(12,45));
}
//Function中的 R apply(T t)
//Math中的 Long round(Double d)
@Test
public void test3(){
Function<Double,Long> func = d -> Math.round(d);
System.out.println(func.apply(23.567));
System.out.println("********* 方法引用 *********");
Function<Double,Long> func1 = Math :: round;
System.out.println(func1.apply(23.567));
}
/*
情况三: 类 :: 实例方法
Comparator中的int compare(T t1 ,T t2)
String中的int t1.compareTo(t2)
*/
@Test
public void test4(){
Comparator<Integer> comp = (t1,t2) -> t1.compareTo(t2);
System.out.println(comp.compare(20,18));
System.out.println("********* 方法引用 *********");
Comparator<Integer> comp1 =Integer :: compareTo;
System.out.println(comp1.compare(20,18));
}
//BiPredicate中的 boolean test(T t1, T t2)
//Integer中的 boolean t1.equal(t2)
@Test
public void test5(){
BiPredicate<Integer,Integer> biPredicate =(t1,t2) -> t1.equals(t2);
System.out.println(biPredicate.test(21,20));
System.out.println("********* 方法引用 *********");
BiPredicate<Integer,Integer> biPredicate1 =Integer :: equals;
System.out.println(biPredicate1.test(20,20));
}
//Function中的 R apply(T t)
//Person中的String getName()
@Test
public void test6(){
Person person = new Person("王", 18);
Function<Person,String> func = (p) -> p.getName();
System.out.println(func.apply(person));
System.out.println("********* 方法引用 *********");
Function<Person,String> func1 = Person ::getName;
System.out.println(func1.apply(person));
}
}
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 + '}';
}
}
package com.test;
import org.junit.Test;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* CLassName: ConstructorReferenceTest
* Package: com.test
* Description:
* 一、构造器引用
* 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致,
* 抽象方法的返回值类型即为构造器所属的类的类型
*
*
* 二、数组引用
* 可以把数组看成一个特殊的类,则写法与构造器引用一致。
*
*
* @Author: JOKER-wqc
* @Version: v1.0
*/
public class ConstructorReferenceTest {
//构造器引用
//Supplier中的 T get()
@Test
public void test(){
Supplier<Person> sup = () -> new Person();
System.out.println(sup.get());
System.out.println("********* 构造器引用 *********");
Supplier<Person> sup1 = Person::new;
System.out.println(sup1.get());
}
//Function中的R apply(T t)
@Test
public void test1(){
Function<Integer,Person> func = (age) -> new Person(age);
System.out.println(func.apply(11));
System.out.println("********* 构造器引用 *********");
Function<Integer,Person> func1 = Person::new;
System.out.println(func1.apply(18));
}
//BiFunction中的 R apply(T t,U u)
@Test
public void test2(){
BiFunction<String,Integer,Person> biFunction = (name,age) -> new Person(name,age);
System.out.println(biFunction.apply("王",18));
System.out.println("********* 构造器引用 *********");
BiFunction<String,Integer,Person> biFunction1 = Person ::new;
System.out.println(biFunction1.apply("轩辕",19));
}
//数组引用
//Function中的 R apply(T t)
@Test
public void test3(){
Function<Integer,String[]> func = length -> new String[length];
System.out.println(Arrays.asList(func.apply(2)));
System.out.println("********* 数组引用 *********");
Function<Integer,String[]> func1 = String[] :: new;
System.out.println(Arrays.asList(func1.apply(5)));
}
}
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));
}