[英]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的方法,則返回MutableList或ImmutableList 。 這樣,該方法的調用者將能夠鏈接由這些接口公開的豐富API的用法。
正如其他人所說的那樣,使用單一方法提供和使用接口,以便在使用Java 8時可以使用lambdas或方法引用來實現它們,這是在不破壞Java 7兼容性的情況下支持Java 8的好方法。
這可以通過提供您的庫方法 ,其適應標准功能類型的Java 8中的一種補充(如Supplier
, (Bi)Consumer
, (Bi)Function
),這樣的Java 8開發人員可以創建他們對Java 8的方法引用API方法。 這意味着它們的簽名與這些功能接口之一匹配,並且它們不會拋出已檢查的異常。 這通常是自然而然的,例如, getFoo()
可以充當Function
而isBar()
充當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.