方法/構造/數組引用
方法引用
當要傳遞給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));}