編程沒有銀彈:探討 Java 8 新增特性的優缺點

2020-12-11 CSDN技術社區

Java 8或許是 迄今為止最令人期待的Java版本,最初定於今年的9月份發布,但由於一系列的安全漏洞問題,目前已推遲到明年的3月份。


Java 8試圖「創新」,根據 微軟對這個詞的定義,就是把其他框架或語言裡成熟的特性「偷」進來。在新版本發布之前,Java社區就已經開始討論Lambda項目、Streams、函數式接口等其他好東西。下面就讓我們一起來看下這些偉大的功能,看看它們各自的優缺點,好讓你更好地應用在項目中。

Streams

集合(Collections)的改進也是Java 8的一大亮點,而讓集合越來越好的核心組件則是「Stream」。它與java.io包裡的InputStream和OutputStream是完全不同的概念,它是一個全新的概念,大家不要混淆。

此外,Stream的出現也並不是要取代ArrayLists或其他集合,它提供了一種操作大數據接口,讓數據操作更容易和更快。Stream是一次性使用對象,一旦被遍歷,就無法再次遍歷。在遍歷時,它具有過濾、映射以及減少遍歷數等功能。每個Stream都有兩種模式:順序執行和並行執行,其能夠利用多核處理器的優勢,並可以使用 fork/join並行方式來拆分任務和加速處理過程。

順序流:

List <Person> people = list.getStream.collect(Collectors.toList());

並行流:

List <Person> people = list.getStream.parallel().collect(Collectors.toList());

顧名思義,當使用順序方式去遍歷時,每個item讀完後再讀下一個item。而使用並行去遍歷時,數組會被分成多個段,其中每一個都在不同的線程中處理,然後將結果一起輸出。

並行流實例:

List originalList = someData;split1 = originalList(0, mid);split2 = originalList(mid,end);new Runnable(split1.process());new Runnable(split2.process());List revisedList = split1 + split2;

由於一個Stream只能被遍歷一次,通常會返回另外一個Stream,可以使用終端方法(terminal method)來獲取有用的結果,終端方法可以是sum()、collect()或toArray()等。在Stream被終止之前,操作的結果不會被實現。

Double result = list.getStream().mapToDouble(f -> f.getAmount()).sum();List<Person> people = list.getStream().filter(f -> f.getAge() > 21).collect(Collectors.toList());

該功能最大的好處是允許使用多核處理器來處理集合,這樣處理速度會更加快速。而最主要的問題則是可讀性。隨著流鏈的加長,很有可能影響可讀性。其它問題則來源於內置的新東西來支持這個新路徑,這些是功能接口和Lambda。

函數式接口

在Java 8裡將會有一個全新的功能——函數式接口(functional interfaces),就是可以在接口裡面添加默認方法,並且這些方法可以直接從接口中運行。

這樣就可以在接口中實現集合的向後兼容,並且無需改變實現這個方法的類,就可以讓Stream放置到接口中。一般而言,在接口中創建一個默認方法,然後實現該接口的所有類都可以使用Stream(無論是默認方法還是非默認方法)。

基本上就是一種多繼承形式,這樣就變成了實現者之間的問題,作為實現人員,必須重寫這些方法,他們可以選擇使用超方法(supermethod),這也就意味著,許多實現接口的類需要改寫。

這有可能是Java 8裡最讓人關心的細節,也許Java 8裡的函數式接口對於熟悉Scala的開發者來說不算新功能,但是他們可能會拿函數式接口與Scala的特徵進行比較。然而,兩者之間不同的是:Java 8裡的函數式接口不能將一個引用指向實現類,而Scala允許通過self關鍵字來實現該操作。會有一些語言狂熱者說,Java 8裡的函數式接口只允許多繼承行為,而不是狀態。而Scala裡的多繼承特徵既可以是行為也可以是狀態。

在Java裡實現事務和其它項目,我們一般會使用 JavaAssist或 cglib的擴展類來構建動態代理和字節碼操作。而Scala的特行可以讓我們更直接地實現。

一方面,函數式接口可能會被以繼承方式濫用,另一方面,它們儘量不與Scala特徵重複。

Lambda

Java 8的另一大亮點是引入Lambda表達式,使用它設計的代碼會更加簡潔。當開發者在編寫Lambda表達式時,也會隨之被編譯成一個函數式接口。下面這個例子就是使用Lambda語法來代替匿名的內部類,代碼不僅簡潔,而且還可讀。

沒有使用Lambda的老方法:

button.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent ae) {System.out.println(「Action Detected」);}});

使用Lambda:

button.addActionListener(e -> {System.out.println(「Action Detected」);});

讓我們來看一個更明顯的例子。

不採用Lambda的老方法:

Runnable runnable1 = new Runnable() {@Overridepublic void run() {System.out.println("Running without Lambda");}};

使用Lambda:

Runnable runnable2 = () -> { System.out.println("Running from Lambda"); };

正如你所看到的,使用Lambda表達式不僅讓代碼變的簡單、而且可讀、最重要的是代碼量也隨之減少很多。然而,在某種程度上,這些功能在Scala等這些JVM語言裡已經被廣泛使用。

並不奇怪,Sclala社區是難以置信的,因為許多Java 8裡的內容看起來就像是從Scala裡搬過來的。在某種程度上,Java 8的語法要比Scala的更詳細但不是很清晰,但這並不能說明什麼,如果可以,它可能會像Scala那樣構建Lambda表達式。

一方面,如果Java繼續圍繞Lambda來發展和實現Scala都已經實現的功能,那麼可能就不需要Scala了。另一方面,如果它只提供一些核心的功能,例如幫助匿名內部類,那麼Scala和其他語言將會繼續茁壯成長,並且有可能會凌駕於Java之上。其實這才是最好的結果,有競爭才有進步,其它語言繼續發展和成長,並且無需擔心是否會過時。

Java time

Time在Java裡已有很長一段時間,首先出現的java.util.Date這個包,其次還有java.sql.Date、Calendar。但處理時間和日期需要大量的monkey代碼,因此,像Joda Time等第三方庫因此誕生。姍姍來遲,Oracle終於決定在Java裡添加一個 java.time包來清理各種時間接口。它看起來很符合現在開發者的胃口,擁有各種各樣的時間API。

Java API可以處理一些時空連續體方面的特性,比如距離、質量、重量等,這是值得稱讚的,但我仍然認為 Currency會處理得更好。我認為Java API需要好好地修剪而不是添加更多的東西,並且首先Java API應該對這些基本元素提供標準的兼容。

Nashorn

Nashorn是Rhino的接替者,該項目的目的是基於Java實現一個輕量級高性能的JavaScript運行環境。

JDK 7中添加了invokeDynamic,其主要是用來支持非Java語言,尤其是動態語言。而JDK 8中的Nashorn將會給開發者提供一個更加實用的JavaScript實現。事實上,Oracle已經有了他自己的Node.js實現,叫做Node.jar。這似乎比在Java裡運行JavaScript更加吸引人。

Accumulators

自從JDK中集成了 java.util.concurrent以來,該特性並沒有停止發展。相反,JDK 8將構建於JDK 7和fork/join框架之上,並通過加法器(adders)和累加器(Accumulators)得到了進一步的發展。

首先是同步。但是,如果你使用同步在多線程之間進行增量計數,那麼同步有可能難以負擔。在Java 6中通過讓非競爭鎖更廉價(cheap)來使同步不那麼難以負擔。其中大多數會使用Vector來提升老應用程式性能,幾乎每一個單線程都受到了Java Activation Framework的影響。

Java.util.concurrent包使得線程池和其他相對複雜的多線程結構變得更好,但是,倘若你想要通過跨線程來增加一個變量,那麼就有點大材小用了。對此,我們採用一種比真正的鎖更輕更快的原子。在JDK 8中,我們採用Accumulators和adders,這些要比原子輕量多了,對於大多數異構代碼來說,這些足以滿足它們的需求,如果線程太多,那麼可以增加一個計數器。但想要看到類似map/reduce實現或統計跨線程之間的總和,你仍然需要使用原子,因為如果要讀取這些跨線程的值,累積的順序是無法得以保證的。

HashMap修復

在Java中使用String.hashCode()實現已是大家熟知的bug。如果在特定的代碼中引入HashMap,可能會導致拒絕服務攻擊。基本上,如果有足夠多的參數hash到相同值,那麼可能會消耗過多的CPU時間。

通常,HashMap bucket採用鍊表的方式來存儲map條目。使用此算法存在大量的衝突,並且增加了O(1)到O(N)這種哈希變化的複雜性,為了解決這一問題,通過採用平衡tree算法來降低複雜度。

TLS SNI

SNI是 伺服器名稱標識(Server Name Identification)的縮寫,由於大多數公共網站的訪客數量不是太多,幾乎很少能達到數百萬用戶。很多網站都使用相同的IP位址和基於名字的虛擬主機,比如我訪問 podcasts.infoworld.com和 www.infoworld.com,最後的網址是一樣的,但訪問的主機名是不一樣的,所以我有可能會訪問到不同的Web頁面。然而,因為SSL,我可能無法分享IP位址。由於HTTP主機頭是建立在基於命名的虛擬主機上,並且主機也是依賴SSL來實現加密/解密的,所以,不得不為每個SSL證書申請不同的IP位址。

在最近幾年都是採用SNI來解決這一問題的,Java也不例外。這種方式得到了大多數瀏覽器的支持,現在Apache和Java也支持它。這意味著過不了多久,我們就可以看到Apache和基於Java的伺服器使用Oracle的SSL實現來支持SNI,稱作 JSSE。

總結

總之,Java 8包含了一大堆非常實用的特性,這也是許多開發者想使用最新版本的原因之一。在我看來,Stream是最好的一個特性。但願並行集合也能夠為其進程性能帶來一些提升。而函數式接口可能並不會像預期中的那樣好用,萬一使用不當,可能會給開發者帶來很多麻煩。

本文只是總結了部分Java 8新特性,我們相信,在發布的時候將會有更多新特性與大家見面。你可以通過Simon Ritter在JavaOne 2013大會上的演講PPT來了解目前已經添加到Java 8中的55個新特性。

至於該如何取捨,各位開發者應該根據自己的實際需求去研究和使用,並不是所有的新特性就是好的,它們也存在優缺點。(編譯:張紅月/責編:王果)

英文來源: InfoWorld

本文為CSDN編譯整理,未經允許不得轉載,如需轉載請聯繫market#csdn.net(#換成@)

CSDN年度盛會SDCC 2013中國軟體開發者大會將於8月30-31日在北京新雲南皇冠假日酒店舉行。本屆大會的主題為「軟體定義未來」,將邀請近百名國內外業界領袖和知名技術專家共論技術熱點與最佳實踐。

>>>報名參會

相關焦點

  • 研發周報:Java稱霸程式語言排行榜
    精彩內容如下:>>>程式語言類1. TIOBE 2013年8月程式語言排行榜:Java領銜稱霸TIOBE公布了2013年8月份程式語言排行榜,本月變化較大的是Java與C位置互換,領銜稱霸,份額略有上升。前三甲為Java、C、C++。
  • Java敗給Python?不!我有話說
    最近市場上經常把Python和Java程式語言拿出來進行比較,我們承認Python發展速度確實很快,也是一門很容易上手的程式語言,可是程式語言也是各有各的優缺點,不能因為一門語言的興起而忽略了其他的程式語言,要不Java為什麼總能在程式語言排行榜的前三名呢?說明Java的性能上還是有優點的。也是程式設計師心裡最流行的程式語言。
  • 【終極版】Java8 新特性全面介紹,強烈建議收藏
    一、介紹Java 8 已經發布很久了,很多報導表明 Java 8 是一次重大的版本升級,雖然我們的 JDK 環境也升級到1.8,但是在日常的開發過程中,使用最多的編程風格還是停留在 JDK1.7。Java8 新增了非常多的特性,主要有以下幾個:Lambda 表達式:Lambda 允許把函數作為一個方法的參數(函數作為參數傳遞到方法中)函數式接口:指的是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口,這樣的接口可以隱式轉換為 Lambda 表達式
  • Java四大名著是什麼?java程式設計師提高技能的經典編程書籍推薦
    java編程的小夥伴有參考。學任何語言,基本的語法知識不能少,首推,Java四大名著( java編程思想+Effective java中文版+Java核心技術卷12),下面來具體介紹以下包含Java四大名著在內的java程式設計師類圖書。
  • 如何零基礎學好Java編程
    不同人考慮的問題不同,看法也不近相同,有人覺得Java完全可以自學沒有必要花錢學習,有人則認為,自學要學到什麼時候,能不能學會還是個問題,花費了時間還沒有效果,參加Java培訓的雖然會有支出,但成功率要比自學高不少。和一群小夥伴共同學習,也有學習的氣氛,也能更快的成長。
  • 為什麼函數式編程在Java中很危險?
    但奇怪的是,我和我的同事並沒有為Haskell、Scheme、Lisp、Clojure、Scala而編程,這個行業裡的絕大部分人都會使用Python、 Ruby、Java或C#等編程,因為它們用起來比較順手。但在Java中,函數式編程卻是低效且危險的。
  • Java基礎知識點面試手冊(線程+JDK8)
    此為下篇,內容包括:高並發編程,Java8新特性。高並發編程多線程和單線程的區別和聯繫:答:在單核 CPU 中,將 CPU 分為很小的時間片,在每一時刻只能有一個線程在執行,是一種微觀上輪流佔用 CPU 的機制。
  • 原創】Java並發編程系列01|開篇獲獎感言
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫為什麼要學並發編程我曾聽一個從事15年開發工作的技術人員說過並發編程是Java語言的重要特性之一,它能使複雜的代碼變得更簡單,從而極大地簡化複雜系統的開發。並發編程可以充分發揮多處理器系統的強大計算能力,隨著處理器數量的持續增長,如何高效的並發變得越來越重要。
  • 九年程式設計師推薦java書籍
    評分排行榜一張圖展示前九名的書籍,其中包含了不同版本的java編程思想,可見java編程思想這本黑皮書的重要性!同時可以從這 9 本書籍當中看出,java開發者關注點主要是在編程思想&設計模式&java虛擬機&jdk這幾個方面,同時也很注重java相關的最佳實踐.
  • Java 8裡面 lambda 的最佳實踐
    ,JDK7最多,其次是6和8,這是好事!在8裡面Lambda是最火的主題,不僅僅是因為語法的改變,更重要的是帶來了函數式編程的思想,我覺得優秀的程式設計師,有必要學習一下函數式編程的思想以開闊思路。所以這篇文章聊聊Lambda的應用場景,性能,也會提及下不好的一面。Java為何需要Lambda1996年1月,Java1.0發布了,此後計算機編程領域發生了翻天覆地的變化。
  • 跟我學java編程—Java字符串類型
    例如:「I want to learn Java programming」、「我要學Java編程」、「3+5=8」、「abc」等等。四則運算器程序需要存儲用戶輸入的計算表達式,計算表達式由多個字符組合而成,用前面所掌握的Java數據類型,不適合存儲計算表達式。程序需要一個新的類型來存儲計算表達式,這個新的類型就是字符串類型。
  • 8月程式語言排行榜:C語言擊敗Java 排名第一,新手學C語言還是Java?
    這兩年,程式語言排行榜榜首位置,不是C語言,就是Java。以下為具體榜單信息:TIOBE 8 月 TOP 10 程式語言而Java是一門面向對象程式語言,不僅吸收了C++語言的各種優點,還摒棄了C++裡難以理解的多繼承、指針等概念,具有功能強大和簡單易用兩個特徵,適合於網際網路+應用程式開發。Java語言相比於C應用層面更廣,也比C更容易學。其次,Java的就業前景更廣、薪資更高。
  • JAVA8 新特性詳解
    一、接口的默認方法在接口中新增了default方法和static方法,這兩種方法可以有方法體1、static方法示例代碼class java.lang.StringSupplier 接口Supplier 接口返回一個任意泛型的值,和Function接口不同的是該接口沒有任何參數Supplier<Person> personSupplier
  • 關於每個版本特性的Java 面試題
    ;        }    }} 參考文章:Java5新特性及使用11)新增Formatter格式化器(Formatter)Formatter 類是Java5中新增的 printf-style 格式化字符串的解釋器,它提供對布局和對齊的支持,提供了對數字,字符串和日期/時間數據的常用格式以及特定於語言環境的輸出。
  • 大學生學Java編程開發真的很值得
    是最值得學習的程式語言嗎?  其實我們評價一種開發語言就像我們評價一個人一樣,如果只是說他很好,最值得學習,這樣的評價看起來就太籠統了,而且一點也不具有說服力,所以今天場長大大就把java做一場擬人化處理,想像我們面對的java是一個帥氣的小夥子,當然你如果願意也可以把她想像為一名陽光美少女,畢竟從Java的出生年紀看,她真的只是個20歲活力滿滿的陽光少女喲。
  • 2020Java程式語言發展現狀報告
    2020年博學谷對Java課程進一步升級,包括升級課程體系、打造企業級項目庫,豐富的直播類型、4對1全程督導、就業服務升級2.0、新增心理輔導服務。以幫助更多對Java感興趣的同學們順利學習到紮實的技術。Java程式語言已經歷經25年的發展,為何始終都是企業優選的程式語言呢?今天我們一起來了解一下2020年Java程式語言的發展現狀報告。
  • 2018年學習編程是學習JAVA好還是學習python好?
    2018年世界程式語言熱度排名python首次超出java,很多同學想學習編程,但是選擇哪門語言方面很糾結,過去幾年java一直排名第一,選擇java無話可說,新的熱度是不是會持續下去,Java還那麼吃香嗎?成為選擇的一個就節點。
  • 深度解讀 深入淺出 Java 8 Lambda 表達式
    簡而言之,在 Java 裡將普通的方法或函數像參數一樣傳值並不簡單,為此,Java 8 增加了一個語言級的新特性,名為 Lambda 表達式。為什麼 Java 需要 Lambda 表達式?如果忽視註解(Annotations)、泛型(Generics)等特性,自 Java 語言誕生時起,它的變化並不大。
  • 給Java新手的一些建議——Java知識點歸納(Java基礎部分)
    面向對象編程的概念這是一個java的核心概念,對於任何java開發者都需要熟練掌握。Java中很多特性或者說知識點都是和java面向對象編程概念相關的。在我的理解,一個好的開發者不僅僅需要了解這些特性(知識點)本身,也更需要知道這些對象在java的面向對象編程概念中是如何體現出來的,這樣更有利於開發者掌握java這門開發語言,以及其他面向對象編程的語言。
  • 深入淺出Rhino:Java與JS互操作
    Java SE的亮點之一就是Oracle詳細闡述Java SE 8路線圖。我們先來看看Java SE 8新增了哪些主要功能:  Java SE 8 新增主要功能  1、為提高開發人員工作效率,更好地利用多核處理器和增強對Java集合APIs的大容量數據處理功能,推出的Lambda表達式(「關閉」)。