首頁  >  文章  >  Java  >  Java缺失的特性擴展方法是什麼

Java缺失的特性擴展方法是什麼

WBOY
WBOY轉載
2023-05-20 16:58:431471瀏覽

    什麼是擴充方法

    擴充方法,就是能夠直接向現有型別「新增」方法,而無需建立新的派生類型、重新編譯或以其他方式修改現有類型。在呼叫擴展方法時,與呼叫實際在類型中定義的方法相比沒有明顯的差異。

    為什麼需要擴充方法

    考慮要實現這樣的功能:從Redis 取出包含多個商品ID的字串後(每個商品ID使用英文逗號分隔),先將商品ID進行去重(並且能夠維持元素的順序),最後再使用英文逗號將各個商品ID進行連接。

    傳統寫法:

    使用 Stream 寫法:

    假設在Java 中能實作擴充方法,並且我們為陣列新增了擴充方法 toList(將陣列變成 List) ,為 List 新增了擴充方法 toSet(將 List 變成 LinkedHashSet),為 Collection 新增了擴充方法 join(將集合中元素的字串形式使用給定的連接符號進行連接),那麼我們將可以這樣寫入程式碼:

    相信此刻你已經有了為什麼需要擴展方法的答案:

    可以對現有的類別庫,進行直接增強,而不是使用工具類別

    相比使用工具類,使用類型本身的方法寫程式碼更流暢更舒適

    程式碼更容易閱讀,因為是鍊式調用,而不是用靜態方法套娃

    在Java 中怎麼實現擴展方法

    我們先來問問最近大火的ChatGPT:

    Java缺失的特性擴展方法是什麼

    #ChatGPT的看法是,在Java中,擴展方法是透過提供的工具類的靜態方法實作的。所以接下來我將介紹一種全新的黑科技:

    Manifold

    準備條件

    Manifold 和Lombok 的工作原理類似,都是透過註解處理器在編譯時進行處理。為了有效地使用Manifold,需要在IDEA中安裝Manifold IDEA插件

    然後再在專案pom 的 maven-compiler-plugin 中加入 annotationProcessorPaths:

    如果您的專案中使用了Lombok,要將Lombok 也加入 annotationProcessorPaths:

    寫擴充方法

    JDK 中,String 的 split 方法,使用的是字串作為參數,即 String[] split(String)。我們現在來為 String 新增一個擴充方法 String[] split(char):依照給定的字元進行分割。

    基於Manifold,寫擴充方法:

    可以發現本質上還是工具類別的靜態方法,但有一些要求:

    工具類別需要使用Manifold 的 @Extension 註解

    靜態方法中,目標類型的參數,需要使用 @This 註解

    #工具類別所在的包名,需要以 extensions.目標類型全限定類別名稱 結尾

    —— 用過C# 的同學應該會心一笑,這就是模仿的C# 的擴展方法。

    關於第 3 點,之所以有這個要求,是因為 Manifold 希望能快速找到專案中的擴充方法,避免對專案中所有的類別進行註解掃描,提升處理的效率。

    具備了擴充方法的能力,現在我們就可以這樣呼叫了:

    Amazing!而且你可以發現,System.out.println(numStrs.toString()) 列印的居然是陣列物件的字串形式 —— 而不是陣列物件的位址。瀏覽反編譯後的App.class,觀察到擴充方法的呼叫被取代成了靜態方法呼叫

    Java缺失的特性擴展方法是什麼

    而陣列的 toString 方法,使用的是Manifold 為陣列定義的擴充方法 ManArrayExt.toString(@This Object array):

    Java缺失的特性擴展方法是什麼

    [Ljava.lang.String;@511d50c0 什麼的,Goodbye,再也不見~

    #因為是在編譯期將擴展方法的調用替換為靜態方法調用,所以使用Manifold 的擴展方法,即使調用方法的對像是 null 也沒有問題,因為處理後的程式碼是把 null 作為參數傳遞到對應的靜態方法。例如,對於Collection進行擴充:

    然後呼叫的時候:

    java.lang.NullPointerException,Goodbye,再也不見~

    陣列擴充方法

    Java缺失的特性擴展方法是什麼

    我們看到 List 這樣的寫法:@Self 是用來表示被註解的值應該是什麼型,如果是 @Self,也就是 @Self(false),表示被註解的值和 @This 註解的值是同一個型別;@Self(true) 則表示是陣列中元素的型別。

    對於物件數組,我們可以看到 toList 方法傳回的就是對應的 List(T 為數組元素的型別):

    Java缺失的特性擴展方法是什麼

    但如果是原始類型數組,IDEA 指示的回傳值是:

    Java缺失的特性擴展方法是什麼

    但是我用的是Java 啊,擦除法泛型怎麼可能擁有 List 這麼偉大的函數——所以你只能用原生型別來接收這個回傳值:)

    Java缺失的特性擴展方法是什麼

    —— 許個願,希望 Project Valhalla 早日GA。

    我們常在各個專案中看到,大家先把​​某個物件包裝成 Optional,然後再進行 filter、map 等。透過 @Self 的型別映射,你可以這樣為 Object 加入一個非常實用的辦法:

    那麼任何對象,都會擁有 asOpt() 方法。

    比起之前的需要包裝一下的不自然:

    你現在可以自然而然的使用 Optional:

    #當然,Object 是所有的類別的父類,這樣做是否合適,還是需要謹慎的思考。

    擴充靜態方法

    我們都知道 Java9 為集合加入了工廠方法:

    是不是很眼饞?因為如果用的不是Java9 以上版本(Java8:直接報我身份證就行),你就得用Guava 之類的庫—— 然而 ImmutableList.of 用起來終究是比不上 List.of 這樣的正統來的自然。

    沒關係,Manifold 說:「無所謂,我會出手」。基於Manifold 擴展靜態方法,就是在擴展類別的靜態方法上,也加上 @Extension:

    然後你就可以欺騙自己已經用上了Java8 之後的版本—— 你發任你發,我用Java8。

    BTW,因為 Object 是所有類別的父類,如果你給 Object 新增靜態擴充方法,那麼表示你可以在任何地方直接存取這個靜態方法,而不需要import —— 恭喜你,解鎖了「頂級函數」。

    以上是Java缺失的特性擴展方法是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除