2014-04-20 39 views
8

我正在開發一個Java開源庫,並希望確保它對Java 8用戶很方便,並且儘可能利用Java 8中的新概念(lambdas等)爲Java 8增強庫,同時保持向後兼容性

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

我可以採用哪些有用的Java 8特性,這對於庫用戶是有利的,而不會破壞老版本Java用戶的庫兼容性?

+0

也許你可能會創建一個Java8 fork,並讓舊版本可用於需要它的人。 – MightyPork

+2

我想說你可以做的就是在整個API中使用函數接口,這樣JDK 8中的用戶就可以使用lambda表達式和方法引用來實現它們,這就是它。 –

回答

2

我不知道你的圖書館,這個建議可能會稍微偏離

Lambdas:別擔心。任何功能接口都可以使用Lambda表達式來實現。

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

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

默認方法:通過一切手段,使用這些!它們是一種快速/便宜/好方法,可以在不破壞現有實現的情況下加強現有實現。您添加的所有默認方法將自動用於實現類。但是,這些將需要第二個庫部分,因此您應該在基本庫中提供基本接口,並從協同庫擴展接口。

不要分叉庫,放棄舊的,因爲仍然有許多開發人員不能使用Java 8甚至Java 7。 Android,請保持兼容性。

2

如果您希望您的代碼能夠被Java 6消耗的虛擬機使用,那麼您的必須使用Java 6語言兼容性來編寫。唉。字節碼格式嚴格地從6變爲7,所以7和8的代碼不會加載到6.(我發現這與我自己的代碼遷移到7;即使當我所有使用的是多catch - 應該可寫在6字節碼 - 我不能建立它的6個目標。編譯器拒絕。)

我還沒有試驗8,但你必須小心,因爲如果你依賴任何新的Java包或課程,你會仍然無法使用舊版本;老的虛擬機根本無法訪問相關的類,也無法加載代碼。特別是,lambdas definitely won't work

那麼,我們可以針對不同的類文件版本嗎?沒有任何源碼和目標的組合可以讓javac對此感到滿意。

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

因此,根本沒有辦法將Java源代碼與lambda編譯爲Java 8之前的類文件版本。

我的一般看法是,如果您要支持舊版本的Java,則必須使用舊版本的Java來執行此操作。你可以使用Java 8工具鏈,但你需要Java 7或Java 6源碼。你可以可以通過分支代碼來實現它,維護你想支持的所有Java版本的版本,但是這遠比你可以作爲一個獨立的開發者合理得多。選擇最低版本,並與那(並親吻那些多汁的新功能,現在再見,唉)。

+0

爲了記錄,我目前使用Java 7作爲我的主要目標平臺。我得到的代碼嚴格要求Java 7的特性(改進的文件系統處理),我根本不針對智能手機。 –

+1

+1表示支持舊Java版本需要使用該版本進行構建。可以試試'$ JAVA8/bin/javac -source 1.7 -target 1.7',但即使這樣也會讓Java 8庫的依賴性無意中蠕動。這樣做會導致一個消息,如'warning:[options] bootstrap class path沒有與-source 1.7'一起設置,它基本上說你必須將引導類路徑設置爲指向Java 7.在這一點上,你可能只是以及使用Java 7工具鏈。 –

2

如果您在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中使用Functional Interfaces。如果您的方法將Runnables,Callables,Comparators等作爲參數,那麼Java 8的用戶將能夠傳遞lambda表達式。您也可以創建自己的單抽象方法接口。如果你發現你需要函數和謂詞,我建議重複使用GS Collections或番石榴而不是自己寫的函數。

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

0

如所述由他人,提供和使用接口與單個方法,使得它們可以使用Java 8時的支持Java 8而不會斷裂的Java 7的兼容性的好方法使用的lambda或方法的引用來實現。


這可以通過提供方法你的庫,融入標準函數類型的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)他們都不可以再使用的方法引用作爲Foo::bar將是不明確的。消除或重命名這些方法之一。

,這種方法不具有多線程使用時會導致令人驚訝的行爲無證內部狀態是很重要的。否則,它們不能被並行流使用。


不應被低估的另一個機會是使用爲類,接口,符合由Java API 8引入了模式的成員。例如。如果您必須爲您的庫引入某種過濾器接口並使用適用於您的庫的測試方法,則應該將接口Predicate和方法test命名爲將它與Java 8的類似命名函數接口相關聯。