想更詳細的了解JDK10新特性可以瀏覽官方介紹
JDK10 新特性目錄導航:
- 局部變量類型推斷
- 將JDK多存儲庫合並為單儲存庫
- 垃圾回收接口
- 並行Full GC 的G1
- 應用數據共享
- 線程局部管控
- 移除Native-Header Generation Tool (javah)
- Unicode 標簽擴展
- 備用內存設備上分配堆內存
- 基於實驗JAVA 的JIT 編譯器
- Root 證書
- 基於時間的版本控制
局部變量類型推斷
很多人抱怨Java是一種強類型,需要引入大量的樣板代碼。甚至在這些情況下,給定好變量名,通常很清楚發生了什么,明顯類型聲明往往被認為是不必要的。許多流行的編程語言都已經支持某種形式的局部變量類型推斷:如C++ (auto), C# (var), Scala (var/val), Go (declaration with :=)等。
JDK10 可以使用var作為局部變量類型推斷標識符,此符號僅適用於局部變量,增強for循環的索引,以及傳統for循環的本地變量;它不能使用於方法形式參數,構造函數形式參數,方法返回類型,字段,catch形式參數或任何其他類型的變量聲明。
標識符var不是關鍵字;相反,它是一個保留的類型名稱。這意味着var用作變量,方法名或則包名稱的代碼不會受到影響;但var不能作為類或則接口的名字(但這樣命名是比較罕見的,因為他違反了通常的命名約定,類和接口首字母應該大寫)。
參考一下示例:
var str = "ABC"; //根據推斷為 字符串類型 var l = 10L;//根據10L 推斷long 類型 var flag = true;//根據 true推斷 boolean 類型 var flag1 = 1;//這里會推斷boolean類型。0表示false 非0表示true var list = new ArrayList<String>(); // 推斷 ArrayList<String> var stream = list.stream(); // 推斷 Stream<String>
反編譯class文件:
String str = "ABC"; long l = 10L; boolean flag = true; int flag1 = true; ArrayList<String> list = new ArrayList(); Stream<String> stream = list.stream();
從上面示例可以看出,當我們是用復雜的方法時,不需要特意去指定他的具體類型返回,可以使用var推斷出正確的數據類型,這在編碼中,可以大幅減少我們對方法返回值的探究。
將JDK多存儲庫合並為單存儲庫
為了簡化和簡化開發,將JDK多存儲庫合並到一個存儲庫中。多年來,JDK的完整代碼已經被分解成多個存儲庫。在JDK9 中有八個倉庫:root、corba、hotspot、jaxp、jaxws、jdk、langtools和nashorn。在JDK10中被合並為一個存儲庫。
雖然這種多存儲庫模型具有一些有點,但它也有許多缺點,並且在支持各種可取的源代碼管理操作方面做得很差。特別是,不可能在相互依賴的變更存儲庫之間執行原子提交。例如,如果一個bug修復或RFE的代碼現在同時跨越了jdk和hotspot 存儲庫,那么對於兩個存儲庫來說,在托管這兩個不同的存儲庫中,對兩個存儲庫的更改是不可能實現的。跨多個存儲庫的變更是常見。
垃圾回收接口
這不是讓開發者用來控制垃圾回收的接口;而是一個在 JVM 源代碼中的允許另外的垃圾回收器快速方便的集成的接口。
垃圾回收接口為HotSpot的GC代碼提供更好的模塊化;在不影響當前代碼的基礎情況下,將GC添加到HotSpot變的更簡單;更容易從JDK構建中排除GC。實際添加或刪除GC不是目標,這項工作將使HotSpot中GC算法的構建時間隔離取得進展,但它不是完全構建時間隔離的目標。
並行Full GC 的G1
JDK10 通過並行Full GC,改善G1的延遲。G1垃圾收集器在JDK 9中是默認的。以前的默認值並行收集器中有一個並行的Full GC。為了盡量減少對使用GC用戶的影響,G1的Full GC也應該並行。
G1垃圾收集器的設計目的是避免Full收集,但是當集合不能足夠快地回收內存時,就會出現完全GC。目前對G1的Full GC的實現使用了單線程標記-清除-壓縮算法。JDK10 使用並行化標記-清除-壓縮算法,並使用Young和Mixed收集器相同的線程數量。線程的數量可以由-XX:ParallelGCThreads選項來控制,但是這也會影響用Young和Mixed收集器的線程數量。
應用數據共享
為了提高啟動和內存占用,擴展現有的類數據共享(CDS)特性,允許將應用程序類放置在共享檔案中。
- 通過在不同的Java進程間共享公共類元數據來減少占用空間。
- 提升啟動時間。
- CDS允許將來自JDK的運行時映像文件($JAVA_HOME/lib/modules)的歸檔類和應用程序類路徑加載到內置平台和系統類加載器中。
- CDS允許將歸檔類加載到自定義類加載器中。
線程局部管控
在不執行全局VM安全點的情況下對線程執行回調的方法。讓它停止單個線程而不是全部線程。
移除Native-Header Generation Tool (javah)
JDK10 從JDK中移除了javah 工具。該工具已被JDK8 (JDK-7150368)中添加javac高級功能所取代。此功能提供了在編譯java源代碼時編寫本機頭文件的功能,從而無需使用單獨的工具。
Unicode 標簽擴展
JDK10 改善 java.util.Locale 類和相關的 API 以實現額外 BCP 47 語言標簽的 Unicode 擴展。尤其以下擴展支持:
- cu:貨幣類型
- fw:一周的第一天
- rg:區域覆蓋
- tz:時區
為支持以上擴展,JDK10對以下API進行更改:
- java.text.DateFormat::get*Instance:將根據擴展ca、rg或tz返回實例。
- java.text.DateFormatSymbols::getInstance:將根據擴展rg返回實例。
- java.text.DecimalFormatSymbols::getInstance:將根據擴展rg返回實例。
- java.text.NumberFormat::get*Instance:將根據nu或rg返回實例。
- java.time.format.DateTimeFormatter::localizedBy:將返回DateTimeFormatter 根據ca,rg或rz的實例。
- java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern:將根據rg返回String。
- java.time.format.DecimalStyle::of:將返回DecimalStyle根據nu或rg的實例。
- java.time.temporal.WeekFields::of:將返回WeekFields根據fw或rg的實例。
- java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}:將根據fw或rg返回值。
- java.util.Currency::getInstance:將返回Currency根據cu或rg返回實例。
- java.util.Locale::getDisplayName:將返回一個包含這些U擴展名的顯示名稱的字符串。
- java.util.spi.LocaleNameProvider:將為這些U擴展的鍵和類型提供新的SPI。
備用內存設備上分配堆內存
啟用HotSpot VM以在用戶指定的備用內存設備上分配Java對象堆。隨着廉價的NV-DIMM內存的可用性,未來的系統可能配備了異構的內存架構。這種技術的一個例子是英特爾的3D XPoint。這樣的體系結構,除了DRAM之外,還會有一種或多種類型的非DRAM內存,具有不同的特征。具有與DRAM具有相同語義的可選內存設備,包括原子操作的語義,因此可以在不改變現有應用程序代碼的情況下使用DRAM代替DRAM。所有其他的內存結構,如代碼堆、metaspace、線程堆棧等等,都將繼續駐留在DRAM中。
參考以下使用案例:
- 在多JVM部署中,某些JVM(如守護進程,服務等)的優先級低於其他JVM。與DRAM相比,NV-DIMM可能具有更高的訪問延遲。低優先級進程可以為堆使用NV-DIMM內存,允許高優先級進程使用更多DRAM。
- 諸如大數據和內存數據庫等應用程序對內存的需求不斷增加。這種應用可以將NV-DIMM用於堆,因為與DRAM相比,NV-DIMM可能具有更大的容量,成本更低。
基於實驗JAVA 的JIT 編譯器
啟用基於Java的JIT編譯器Graal,將其用作Linux / x64平台上的實驗性JIT編譯器。Graal是一個基於Java的JIT編譯器,它是JDK 9中引入的Ahead-of-Time(AOT)編譯器的基礎。使它成為實驗性JIT編譯器是Project Metropolis的一項舉措,它是下一步是研究JDK的基於Java的JIT的可行性。
使Graal可用作實驗JIT編譯器,從Linux / x64平台開始。Graal將使用JDK 9中引入的JVM編譯器接口(JVMCI)。Graal已經在JDK中,因此將它作為實驗JIT將主要用於測試和調試工作。要啟用Graal作為JIT編譯器,請在java命令行上使用以下選項:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
Root 證書
在JDK中提供一組默認的root 認證權威(CA)證書。在Oracle的Java SE根CA程序中開源root證書,以使OpenJDK構建對開發人員更有吸引力,並減少這些構建和Oracle JDK構建之間的差異。
cacerts密鑰存儲庫是JDK的一部分,它的目的是包含一組root證書,這些root證書可以用來在各種安全協議中使用的證書鏈中建立信任。然而,JDK源代碼中的cacerts密鑰庫目前是空的。因此,諸如TLS之類的關鍵安全組件在OpenJDK構建中不會默認工作。為了解決這個問題,用戶必須配置和填充cacerts密鑰庫,並使用一組root證書來記錄,例如, JDK 9 release notes。
基於時間的版本控制
在JEP 223 引入的版本字符串方案比以往有了顯著的改進,但是,該方案並不適合未來,現在Java SE平台和JDK的新版本嚴格按照六個月的節奏發布。JEP 223方案的主要困難在於發行版的版本號對於其前身的重要性和兼容性進行了編碼。然而,在基於時間發布模式中,這些品質並不是事先知道的。在發布的開發周期中,它們可能會發生變化,直到最終的功能被集成為止。因此發布的版本號也是未知的。
使用JEP 223的版本號語義,每個在JDK發布版上工作或者在其上構建或使用組件的人都必須先說明發布的發布日期,然后切換到說版本號,已知。維護庫,框架和工具的開發人員必須准備好更改在每個JDK發布周期后期檢查版本號的代碼。這對所有參與者來說都很尷尬和混亂。
因此,這里提出的主要改變是重新編制版本號來編碼,而不是編碼的兼容性和重要性,而是按照發布周期的時間推移。這是更適合基於時間的發布模型,因為每個發布周期,因此每個發布的版本號,總是提前知道。
后續的版本格式為:[1-9][0-9]*((\.0)*\.[1-9][0-9]*)*
該格式可以是任意長度,但前四個被賦予特定含義,如:$FEATURE.$INTERIM.$UPDATE.$PATCH
- $FEATURE:功能發布計數器,不管發布內容如何,都會為每個功能發布增加。功能可能會添加到功能發布中; 如果提前通知提前至少發布一次功能發布,它們也可能會被刪除。如果合理,可能會做出不兼容的更改。
- $INTERIM:臨時版本計數器,對於包含兼容錯誤修復和增強功能的非功能版本遞增,但沒有不兼容的更改,沒有功能移除,也沒有對標准API的更改。
- $UPDATE:更新版本計數器增加了兼容更新版本,可解決新功能中的安全問題,回歸和錯誤。
- $PATCH:緊急修補程序釋放計數器只有在需要生成緊急釋放以解決關鍵問題時才會增加。
版本號永遠不會有零元素結尾。如果一個元素及其后的所有元素在邏輯上具有零值,那么它們全部被省略。
在嚴格六個月的發布模式下,版本號如下所示:
- $FEATURE 每六個月增加一次。如:2018年3月發布的是JDK 10,2018年9月發布的是JDK 11,等等。
- $INTERIM 總是為零,因為六個月的模型不包括臨時版本。在此為保留其靈活性,以便將來對版本模型的修訂可能包括此類版本。
- $UPDATE 在$FEATURE發布后的一個月遞增,之后每三個月遞增一次:如2018年4月發布JDK 10.0.1。7月發布的是JDK 10.0.2等等。\