【java8新特性】——方法引用(四)
一、簡介
方法引用是java8的新特性之一, 可以直接引用已有Java類或對象的方法或構造器。方法引用與lambda表達式結合使用,可以進一步簡化代碼。
來看一段簡單代碼:
上述程序生成一個Stream流,對流中的字符串進行排序并遍歷打印。程序中采用lambda表達式的方式代替匿名類簡化了代碼,然而代碼中兩處lambda表達式都僅僅調用的是一個已存在的方法:String.compareToIgnoreCase、System.out.println,這種情況可以用方法引用來簡化:
public static void main(String[] args) {List<String> strList = Arrays.asList(new String[] { "a", "c", "b" });strList.stream().sorted(String::compareToIgnoreCase).forEach(System.out::println);}對比一下可以看到,上述程序分別采用了類的任意對象的實例方法引用和特定對象的實例方法引用兩種方法引用形式(下一章會講述),采用方法引用的方式可以簡化lambda表達式的寫法。
二、方法引用的具體使用
java8方法引用有四種形式:
- 靜態方法引用 : ClassName :: staticMethodName
- 構造器引用 : ClassName :: new
- 類的任意對象的實例方法引用: ClassName :: instanceMethodName
- 特定對象的實例方法引用 : object :: instanceMethodName
lambda表達式可用方法引用代替的場景可以簡要概括為:lambda表達式的主體僅包含一個表達式,且該表達式僅調用了一個已經存在的方法。方法引用的通用特性:方法引用所使用方法的入參和返回值與lambda表達式實現的函數式接口的入參和返回值一致。
2.1 靜態方法引用
靜態方法引用的語法格式為: 類名::靜態方法名 ,如
System.out::println 等價于lambda表達式 s -> System.out.println(s) ,代碼示例:
靜態方法引用適用于lambda表達式主體中僅僅調用了某個類的靜態方法的情形。
2.2 構造器引用
構造器引用的語法格式為: 類名::new ,如() -> new ArrayList() 等價于 ArrayList::new,代碼示例:
Supplier<List<String>> supplier1= () -> new ArrayList<String>();等價于
Supplier<List<String>> supplier = ArrayList<String>::new;構造器引用適用于lambda表達式主體中僅僅調用了某個類的構造函數返回實例的場景。
2.3 類的任意對象的實例方法引用
類的任意對象的實例方法引用的語法格式為: 類名::實例方法名 , 這種方法引用相對比較復雜,我們來看示例:
一、示例1
Arrays.sort(strs,(s1,s2)->s1.compareToIgnoreCase(s2));等價于
Arrays.sort(strs, String::compareToIgnoreCase);上述示例中,strs為一個String數組,lambda表達式(s1,s2)->s1.compareToIgnoreCase(s2)實現函數式接口的是Comparator接口, 我們看下jdk8中Comparator接口的源碼(截取部分):
@FunctionalInterfacepublic interface Comparator<T> {int compare(T o1, T o2);}而String類的compareToIgnoreCase方法源碼為:
public int compareToIgnoreCase(String str) {return CASE_INSENSITIVE_ORDER.compare(this, str);}可以發現函數式接口Comparator的compare方法比String類的compareToIgnoreCase方法多了一個String類型的入參。看到這里對類的任意對象的實例方法引用的使用可能似懂非懂,下面我們看一個自己實現一個類的任意對象的實例方法引用的示例(示例2)。
二、示例2
public class Student {private String name;private Integer score;public void setNameAndScore(String name, Integer score){this.name = name;this.score = score;System.out.println("Student "+ name +"'s score is " + score);}public static void main(String[] args){/*lambda表達式的用法:TestInterface testInterface = (student, name, score) -> student.setNameAndScore(name, score);*///類的任意對象的實例方法引用的用法:TestInterface testInterface = Student::setNameAndScore;testInterface.set(new Student(), "DoubleBin", 100);}@FunctionalInterfaceinterface TestInterface{// 注意:入參比Student類的setNameAndScore方法多1個Student對象,除第一個外其它入參類型一致public void set(Student d, String name, Integer score);} }看完上述代碼,我們可以總結出類的任意對象的實例方法引用的特性為:
1、方法引用的通用特性:方法引用所使用方法的入參和返回值與lambda表達式實現的函數式接口的入參和返回值一致;
2、lambda表達式的第一個入參為實例方法的調用者,后面的入參與實例方法的入參一致。
2.4 特定對象的實例方法引用
特定對象的實例方法引用的語法格式為: 對象::實例方法名 , 示例代碼:
public class Test {public static void main(String[] args){Test test = new Test();// lambda表達式使用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> test.println(s));// 特定對象的實例方法引用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(test::println);}public void println(String s){System.out.println(s);} }特定對象的實例方法引用適用于lambda表達式的主體中僅僅調用了某個對象的某個實例方法的場景。
三、總結
方法引用使用運算符::連接類(或對象)與方法名稱(或new)實現在特定場景下lambda表達式的簡化表示,使用時要注意方法引用的使用場景及各種方法引用的特性。使用方法引用的好處是能夠更進一步簡化代碼編寫,使代碼更簡潔。
然而作者認為,方法引用代替lambda表達式對代碼的簡化程度遠遠沒有lambda表達式代替匿名類的簡化程度大, 有時反而增加了代碼的理解難度(如2.3節:類的任意對象的實例方法引用),且使用場景的局限性不利于增加或修改代碼,個人認為有時沒有必要刻意使用方法引用~
-
【java8新特性】——lambda表達式與函數式接口詳解(一)
-
【java8新特性】——Stream API詳解(二)
-
【java8新特性】——Optional詳解(三)
-
【java8新特性】——方法引用(四)
-
【java8新特性】——默認方法(五)
總結
以上是生活随笔為你收集整理的【java8新特性】——方法引用(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django 笔记2 -- Django
- 下一篇: Django 笔记3 -- URL