簡體   English   中英

增強Java 8庫,同時保持向后兼容性

[英]Enhance library for Java 8 while keeping backwards compatibility

我正在用Java開發一個開源庫,並希望確保它對Java 8用戶來說很方便,並盡可能利用Java 8中的新概念(lambdas等)

同時我絕對需要保持向后兼容性(庫必須仍然可以用於使用Java 6或7的人)。

我可以采用Java 8的哪些有用功能,這對於庫用戶而言是有益的,而不會破壞舊Java版本用戶的庫兼容性?

我不知道你的圖書館,這個建議可能略有偏差

蘭巴斯 :別擔心。 可以使用Lambda表達式實現任何功能接口。

方法參考 :與lambdas相同,它們應該是可用的。

Streams :如果這適合您的庫,您應該使用它們,但保持兼容性在這里更難。 向后兼容性可以使用第二個庫部件來實現,包圍基礎庫並掛接到它的公共API。 因此,它可以在不放棄Java 6/7的情況下提供額外的糖/功能。

默認方法 :無論如何,請使用這些! 它們是一種快速/廉價/好的方法來增強現有的實現而不會破壞它們。 您添加的所有默認方法都將自動用於實現類。 但是,這些也需要第二個庫部分,因此您應該在基礎庫中提供基本接口,並從companion-library擴展接口。

不要分叉庫,放棄舊庫,因為仍有許多開發人員無法使用Java 8,甚至Java 7.如果您的庫在Android上使用是明智的,請保持兼容性。

如果您希望代碼可供Java 6消耗VM使用,則必須使用Java 6語言兼容性進行編寫。 唉。 字節碼格式從6嚴重變為7,因此7和8的代碼不會加載到6中。(我發現這個用我自己的代碼遷移到7;即使我所使用的都是多catch - 它應該是可寫的在6字節碼中 - 我無法為6個目標構建它。編譯器拒絕了。)

我還沒有嘗試8,但你必須要小心,因為如果你依賴任何新的Java包或類,你仍然無法使用舊版本; 舊的消費虛擬機根本無法訪問相關的類,也無法加載代碼。 特別是, lambdas肯定不會起作用

那么,我們可以針對不同的類文件版本嗎? 沒有源和目標的組合實際上會讓javac對此感到滿意。

 kevin$ $JAVA8/bin/javac -source 1.8 -target 1.7 *.java javac: source release 1.8 requires target release 1.8 

因此,根本無法將帶有lambdas的Java源代碼編譯為Java 8之前的類文件版本。

我的一般看法是,如果要支持舊版本的Java,則必須使用舊版本的Java來實現。 可以使用Java 8工具鏈,但需要Java 7或Java 6源代碼。 可以通過分配代碼來維護代碼,維護你想要支持的所有Java版本的版本,但這比你作為一個單獨的開發人員所證明的要多得多。 選擇最低版本並繼續使用(並親吻那些多汁的新功能再見,唉)。

如果在Java 8中使用任何新的語言功能,則還需要使用Java 8字節碼。

$ javac -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8

這意味着您的選擇非常有限。 您不能使用lambdas,方法引用,默認方法,Streams等,並保持向后兼容性。

Java 8的用戶仍然可以從中受益。 第一種是在公共API中使用功能接口。 如果您的方法將Runnables,Callables,Comparators等作為參數,那么Java 8的用戶將能夠傳入lambdas。 您可能還想創建自己的Single-Abstract-Method接口。 如果您發現需要函數和謂詞,我建議重用GS Collections或Guava附帶的那些,而不是自己編寫。

您可以做的第二件事是使用豐富的集合API,這可以從使用功能接口中受益。 同樣,這意味着使用GS Collections或Guava。 例如,如果您有一個返回List的方法,則返回MutableListImmutableList 這樣,該方法的調用者將能夠鏈接由這些接口公開的豐富API的用法。

正如其他人所說的那樣,使用單一方法提供和使用接口,以便在使用Java 8時可以使用lambdas或方法引用來實現它們,這是在不破壞Java 7兼容性的情況下支持Java 8的好方法。


這可以通過提供您的庫方法 ,其適應標准功能類型的Java 8中的一種補充(如Supplier(Bi)Consumer(Bi)Function ),這樣的Java 8開發人員可以創建他們對Java 8的方法引用API方法。 這意味着它們的簽名與這些功能接口之一匹配,並且它們不會拋出已檢查的異常。 這通常是自然而然的,例如, getFoo()可以充當FunctionisBar()充當Predicate但有時可以通過考慮可能的Java 8使用場景來改進方法。

例如,如果您提供了一個采用兩個參數的方法,則選擇第一個參數更可能是Map的鍵的順序非常有用。 因此,使用方法引用更有可能對Map.forEach有用。

並避免帶有模糊簽名的方法。 例如,如果你有一個帶有實例方法的類Foo ReturnType bar()和一個static方法ReturnType bar(Foo)它們都不ReturnType bar(Foo)用作方法引用,因為Foo::bar是不明確的。 消除或重命名這些方法之一。

重要的是,此類方法沒有未記錄的內部狀態,當由多個線程使用時會導致令人驚訝的行為。 否則它們不能被並行流使用。


另一個不容低估的機會是使用符合Java 8 API引入的模式的類,接口和成員的名稱 例如,如果您必須為您的庫引入某種類型的過濾器接口以及應該與Java 7一起使用的庫,則應該將接口命名為Predicate ,並將方法test與Java 8的類似命名功能接口相關聯。 。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM