方法/构造/数组引用
方法引用
当要传递给Lambda体
的操作已经有实现的方法时就可以使用方法引用,方法引用和构造器引用就是为了简化Lambda表达式
- 方法引用可以看做是Lambda表达式深层次的表达,方法引用本质还是Lambda表达式所以也是函数式接口的一个实例
- 通过方法的名字来指向一个方法可以认为是Lambda表达式的一个语法糖
语法糖(Syntactic sugar)
也译为糖衣语法是指计算机语言中添加的某种对语言的功能没有影响但是更方便程序员使用的语法
- 使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会
方法引用格式: 使用方法引用操作符 “::
” 将类或对象
与方法名
分隔开来,要求Lambda体只有一句语句并且是调用一个对象/类的方法
- 因为
引用的方法的形参和返回值
和函数式接口抽象方法的形参和返回值
都相同,所以引用方法的形参可以省略
- 情况1:
对象::实例方法名
- 情况2:
类::静态方法名
- 情况3:
类::实例方法名
先写一个Employee
实体类
public class Employee {private String name;private Integer id;// get和set方法public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}// 构造方法public Employee() {}public Employee(Integer id) {this.id = id;this.name = name;}public Employee(Integer id,String name) {this.id = id;this.name = name;}
}
**对象::非静态方法
:接口抽象方法a在被重写
时使用了某一个对象的方法b,如果方法a和b的形参列表,返回值类型都相同
,则可以使用方法b实现对方法a的重写替换 **
- Consumer中的void accept(T t)和PrintStream中的void println(T t)形参列表均为(T t)以及返回值均为void
- Supplier中的T get()和Employee中的String getName()形参列表均为空以及返回值均为String
@Test
public void test() {// 使用Lambda表达式Consumer<String> consumer01 = s -> System.out.println(s);consumer01.accept("她的手只有我的手四分之三那麼大");System.out.println("-----------------------------");// 使用方法引用//PrintStream printStream = System.out;//Consumer<String> consumer02 = printStream::println;Consumer<String> consumer02 = System.out::println;consumer02.accept("可我還是沒能抓住");
}
@Test
public void test() {Employee emp = new Employee(1001,"Tom");// 使用Lambda表达式Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());System.out.println("*******************");// 使用方法引用Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}
类::静态方法
: :接口抽象方法a在被重写
时使用了某一个类的静态方法b,如果方法a和b的形参列表,返回值类型都相同
,则可以使用方法b实现对方法a的重写替换
- Comparator中的int compare(T t1,T t2)和Integer中的int compare(T t1,T t2)形参列表均为(T t1,T t2)以及返回值均为int
- Function中的R apply(T t)和Math中的Long round(Double d)返回值和参数列表为泛型
@Test
public void test07() {// 使用Lambda表达式Comparator<Integer> comparator01 = (o1, o2) -> Integer.compare(o1, o2);System.out.println(comparator01.compare(20, 77));System.out.println("----------------------------");// 使用方法引用Comparator<Integer> comparator02 = Integer::compare;System.out.println(comparator02.compare(94, 21));
}@Test
public void test08(){// 使用Lambda表达式Function<Double,Long> function01 = aDouble -> Math.round(aDouble);System.out.println(function01.apply(3.141));System.out.println("------------------------------");// 使用方法引用Function<Double,Long> function02 = Math::round;System.out.println(function02.apply(2.717));
}
类::实例方法
: 抽象方法a在被重写
时使用了某一个对象的方法b,如果方法a和b的返回值类型相同但方法b的形参少一个
,则可以使用方法b实现对方法a的重写替换
- 方法a的形参列表中有n个参数方法b有n-1个参数,方法a的第1个参数作为方法b的调用者,方法a的后n-1个参数与方法b的n-1个参数匹配(类型相同或满足多态)
- Comparator中的int comapre(T t1,T t2)方法和String中的int t1.compareTo(t2)方法
- BiPredicate中的boolean test(T t1, T t2)方法和String中的boolean t1.equals(t2)方法
- Function中的R apply(T t)方法和Employee中的String toString()方法
@Test
public void test5() {// 使用Lambda表达式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"));
}@Test
public void test10(){// 使用Lambda表达式BiPredicate<String,String> biPredicate01 = (o1, o2) -> o1.equals(o2);System.out.println(biPredicate01.test("Kyle", "Kyle"));// trueSystem.out.println("----------------------------------");// 使用方法引用BiPredicate<String,String> biPredicate02 = String::equals;System.out.println(biPredicate02.test("Violet", "Violet"));// true
}@Test
public void test7() {Employee employee = new Employee(1001, "Jerry");// 使用Lambda表达式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));
}@Test
public void test11(){Ememployee employee = new Employee(1001, "Jerry");Function<Stu,String> function01 = employee -> employee.toString();System.out.println(function01.apply(employee));System.out.println("------------------------------");Function<Employee,String> function02 = Employee::toString;System.out.println(function02.apply(employee employee));
}
构造器引用
类名::new
: 要求Lambda体只有一句语句并且是用来创建一个对象,构造方法的形参列表和返回值(构造器对应类的对象)要与接口中抽象方法一致才可以替换
-
Supplier中的T get()和Employee的无参构造方法Employee()
-
Function中的R apply(T t)和Employee的有参构造方法Employee(id)
-
BiFunction中的R apply(T t,U u)和Employee的有参构造方法Employee(id,name)
@Test
public void test1(){// 传统写法Supplier<Employee> sup = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};System.out.println("*******************");// Lambda表达式Supplier<Employee> sup1 = () -> new Employee();System.out.println(sup1.get());System.out.println("*******************");// 构造器引用Supplier<Employee> sup2 = Employee :: new;System.out.println(sup2.get());
}@Test
public void test2(){// Lambda表达式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);}@Test
public void test3(){// Lambda表达式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"));}
数组构造引用
数组类型名[]::new
: 要求Lambda体只有一条语句并且是创建一个数组对象,接口中抽象方法的形参接收的是数组对象的长度
- Function中的R apply(T t)和String[]
@Test
public void test4(){// Lambda表达式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));}