仍不切换到Java 8的6个理由
Java 8很棒。 期。 但是……在我們有機會玩耍并玩弄它之后,就該退出了,避免吃鹽。 所有的好東西都是有代價的,在這篇文章中,我將分享Java 8的主要痛點。請確保在升級和放棄7之前您已經意識到了這些痛點。
1.并行流實際上會使您減速
Java 8將并行性作為最令人期待的新功能之一帶來了希望。 .parallelStream()方法在集合和流上實現此功能。 它將它們分解為子問題,然后在單獨的線程上運行以進行處理,這些子問題可以進入不同的核心,然后在完成后組合在一起。 這一切都是在使用fork / join框架進行的 。 聽起來不錯,它必須加快多核環境中大型數據集的操作,對嗎?
不,如果使用不正確,它實際上會使您的代碼運行緩慢。 慢上大約15% 這個基準,我們跑了,但它可能會更糟糕。 假設我們已經在運行多個線程,并且在其中一些線程中使用了.parallelStream(),從而向池中添加了越來越多的線程。 這很容易變成我們的核心無法處理的事情,并且由于增加了上下文切換而減慢了一切。
基準測試速度較慢,將集合分為不同的組(素數/非素數):
Map<Boolean, List<Integer>> groupByPrimary = numbers .parallelStream().collect(Collectors.groupingBy(s -> Utility.isPrime(s)));同樣,由于其他原因,速度也會變慢。 考慮到這一點,假設我們有多個任務要完成,由于某種原因,其中一個要比其他任務花費更長的時間。 使用.parallelStream()分解它實際上可能會延遲完成較快的任務以及整個過程。 請查看Lukas Krecan的這篇文章,以獲取更多示例和代碼示例。
診斷:并行性及其所有優點也帶來了其他類型的問題需要考慮。 當已經在多線程環境中執行操作時,請記住這一點,并使自己熟悉幕后發生的事情。
2. Lambda表達式的反面
Lambdas。 哦,lambdas。 如果沒有您,我們幾乎可以做所有我們已經可以做的事情,但是您卻增加了很多寬限期,并且擺脫了樣板代碼,因此很容易墜入愛河。 假設我是早上起來 ,想遍歷一隊世界杯球隊并確定他們的身長(有趣的事實:總數達到254):
List lengths = new ArrayList();for (String countries : Arrays.asList(args)) {lengths.add(check(country)); }現在,讓我們通過一個很好的lambda來實現功能:
Stream lengths = countries.stream().map(countries -> check(country));寶貝! 太好了 盡管……雖然通常被視為是一件好事,但在Java中添加諸如lambdas之類的新元素會使它進一步偏離其原始規范。 字節碼完全為OO,并且在游戲中帶有lambda,因此實際代碼與運行時之間的距離會增大。 在Tal Weiss的這篇文章中閱讀有關lambda表達的黑暗面的更多信息。
最重要的是,這一切都意味著您正在編寫的內容和正在調試的內容是兩件事。 堆棧跟蹤越來越大,使調試代碼變得更加困難。
簡單的操作(例如,向列表中添加一個空字符串)將使此簡短的堆棧跟蹤成為可能:
at LmbdaMain.check(LmbdaMain.java:19) at LmbdaMain.main(LmbdaMain.java:34)變成這個:
at LmbdaMain.check(LmbdaMain.java:19) at LmbdaMain.lambda$0(LmbdaMain.java:37) at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.LongPipeline.reduce(LongPipeline.java:438) at java.util.stream.LongPipeline.sum(LongPipeline.java:396) at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526) at LmbdaMain.main(LmbdaMain.java:39)Lambda引發的另一個問題與重載有關:由于Lambda參數在使用它們調用方法時必須轉換為某種東西,并且它們可以轉換為多種類型,因此在某些情況下可能會導致模棱兩可的調用。 Lukas Eder 在此處通過代碼示例對此進行了解釋。
診斷:僅需注意這一點,痕跡可能會不時帶來痛苦,但不會使我們遠離它們。
3.默認方法會分散注意力
默認方法啟用接口本身中功能的默認實現。 這無疑是Java 8帶來的最酷的新功能之一,但是它在某種程度上干擾了我們過去的工作方式。 那么為什么要引入這個呢? 那與它無關嗎?
默認方法背后的主要動機是,如果在某個時候我們需要向現有接口添加方法,則無需重寫實現就可以做到這一點。 與舊版本兼容。 例如,從Oracle Java教程中獲得以下這段代碼,它們在其中添加了指定時區的功能:
public interface TimeClient { // ... static public ZoneId getZoneId (String zoneString) { try {return ZoneId.of(zoneString); } catch (DateTimeException e) {System.err.println("Invalid time zone: " + zoneString +"; using default time zone instead.");return ZoneId.systemDefault();} }default public ZonedDateTime getZonedDateTime(String zoneString) {return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));} }就是這樣,問題解決了。 還是? 默認方法混淆了接口和實現的分離。 在錯誤的手中,仿佛類型層次結構不會自己糾結,現在我們需要馴服這種新生物。 在Oleg Shelajev在RebelLabs上的帖子中了解有關此內容的更多信息。
診斷:當您拿著錘子時,所有東西都看起來像釘子,請牢記堅持其原始用例,當重構引入新的抽象類時,現有接口的演變毫無意義。
繼續進行一些遺失,仍在我們身邊或尚未完全存在的事情:
4.為什么您是
Jigsaw項目的目標是使Java模塊化并將JRE分解為可互操作的組件。 首先,其背后的動機來自對更好,更快,更強大的 Java嵌入式的渴望。 我試圖避免提及“物聯網”,但是我在那說了。 減小JAR大小,提高性能和提高安全性是這個雄心勃勃的項目所具有的更多希望。
那在哪呢 甲骨文首席Java架構師Mark Reinhold表示,拼圖剛進入了第二階段 ,已經通過了探索階段,現在正在將其轉換為生產質量設計和實現。 該項目最初計劃在Java 8中完成,然后推遲到Java 9,有望成為其旗艦新功能之一。
診斷:如果這是您要等待的主要內容,則Java 9將于2016年推出。與此同時,仔細研究一下,甚至可能會涉及到Jigsaw-dev郵件列表。
5.仍然存在的問題
檢查異常
沒有人喜歡樣板代碼,這就是lambda如此受歡迎的原因之一。 考慮樣板異常,無論邏輯上是否需要捕獲或與檢查異常相關 ,您仍然需要捕獲它。 即使這是永遠不會發生的事情,例如永遠不會觸發的異常:
try {httpConn.setRequestMethod("GET"); }?catch (ProtocolException pe) { /* Why don’t you call me anymore? */ }原語
它們仍然在這里,正確使用它們很痛苦 。 將Java與純粹的面向對象的語言區別開來的一件事是,批評說Java的刪除對其性能沒有重大影響 。 只是說,所有新的JVM語言都沒有它們。
操作員超載
Java的父親James Gosling在一次采訪中曾說過:“我忽略了運算符重載,這是一個非常個人的選擇,因為我看到太多的人在C ++中濫用它”。 有點道理,但是對此有很多不同意見。 其他JVM語言確實提供了此功能,但另一方面,它可能會導致代碼如下所示:
javascriptEntryPoints <<= (sourceDirectory in Compile)(base =>((base / "assets" ** "*.js") --- (base / "assets" ** "_*")).get )來自Scala Play框架的實際代碼行,嗯,我現在有點頭暈。
診斷:這些是否是真正的問題? 我們都有自己的怪癖,這些都是Java的怪癖。 在將來的版本中可能會發生意外的情況,并且會有所變化,但是向后兼容性以及其他方面的兼容性使它們始終與我們保持聯系。
6.函數式編程–還不完全
盡管以前很尷尬,但以前使用Java可以進行函數式編程。 Java 8借助lambda對此進行了改進。 這是最受歡迎的,但沒有以前描述的那么大。 絕對比Java 7更優雅,但仍需要向后彎曲才能真正發揮作用。
關于此問題的最激烈的評論之一來自Pierre-yves Saumont,他在一系列文章中仔細研究了函數式編程范例與在Java中實現它們之間的區別。
那么Java還是Scala? Java中采用功能更強大的現代范例對Scala表示認可,因為Scala一直在使用lambda。 Lambda確實引起了很大的反響,但是還有很多特性,例如特征,懶惰的評估和不可變的特性等,它們會產生很大的影響。
診斷:不要被lambda分散注意力,在Java 8中函數式編程仍然很麻煩。
翻譯自: https://www.javacodegeeks.com/2014/07/6-reasons-not-to-switch-to-java-8-just-yet.html
總結
以上是生活随笔為你收集整理的仍不切换到Java 8的6个理由的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hibernate隐藏的宝石:poole
- 下一篇: 电动自行车备案登记备案平台(电动自行车备