歡迎光臨
每天分享高質量文章

JDK 10 的 109 項新特性

(點選上方公眾號,可快速關註)


來源:開源中國,

www.oschina.net/translate/109-new-features-in-jdk-10

雖然感覺 JDK9 釋出才僅僅幾周的時間,然而,隨著新的 OpenJDK 的釋出節奏,JDK10 已經到達釋出候選里程碑階段。

我看過各種關於 JDK10 新特性的部落格,但是它們都傾向於關註透過 JEPS 定義的大方面。這篇博文,我將看看是否可以羅列出 JDK10 中已經發生變化的方方面面(包括新增的和剔除的)。

有時候,我會做一些關於 Java SE 的報告會。之前我在“ JDK9 的 55 個新特性”的報告會上曾開玩笑說:下次我將做的恐怕是“ JDK10 的 5 個新特性”。然而事實證明,即使僅有六個多月的開發時間,JDK10 依然超乎想象。

即便我不再為 Oracle 工作,我也在此先做一個“安全港宣告”,以便消除誤會。這個串列是由下麵這些公開可用的資訊整理編輯的:JDK Enhancement Proposals (JEPs)、the OpenJDK bug database 和 Java SE 10 public review specification (JSR 383) 。當然,儘管我已盡可能的研究以保證資訊準確,但在 JDK 10 最終釋出之前仍可能會發生變化。

大事記

JDK10 包含 12 個JEP (改善提議):

[286]區域性變數型別推斷 :對於開發者來說,這是 JDK10 唯一的真正特性。它向 Java 中引入在其他語言中很常見的  var   ,比如 JavaScript 。只要編譯器可以推斷此種型別,你不再需要專門宣告一個區域性變數的型別。一個簡單的例子是:

var x = new ArrayList();

這就消除了我們之前必須執行的 ArrayList 型別定義的重覆。我鼓勵你們去讀 JEP ,因為上面有一些關於這個句法是否能用的規則。

有趣的是,需要註意 var 不能成為一個關鍵字,而是一個保留字。這意味著你仍然可以使用 var 作為一個變數,方法或包名,但是現在(儘管我確定你絕不會)你不能再有一個類被呼叫。

[310]應用類資料共享(CDS) :CDS 在 JDK5 時被引進以改善 JVM 啟動的表現,同時減少當多個虛擬機器在同一個物理或虛擬的機器上執行時的資源佔用。JDK10 將擴充套件 CDS 到允許內部系統的類載入器、內部平臺的類載入器和自定義類載入器來載入獲得的類。之前,CDS 的使用僅僅限制在了 bootstrap 的類載入器。

[314]額外的 Unicode 語言標簽擴充套件:這將改善 java.util.Locale 類和相關的 API 以實現額外 BCP 47 語言標簽的 Unicode 擴充套件。尤其是,貨幣型別,一週的第一天,區域改寫和時區等標簽現在將被支援。

[322]基於時間的版本控制:正如我在之前的部落格中所討論的,我們的 JDK 版本字串格式幾乎與 JDK 版本一樣多。有幸的是,這是最後需要使用到的,我們可以堅持用它。這種格式使用起來很像 JDK9 中介紹的提供一個更加語意的形式。有一件困擾我的事是包含了一個 INTERIM 元素,正如 JEP 提議中所說,“永遠是0”。好吧,如果永遠是0,那它有什麼意義呢?他們說這是為未來使用做保留,但我仍不是很贊同。我認為,這有些冗餘繁雜。這也消除了在 JDK9 中有過的相當奇怪的情形。第一次更新是 JDK 9.0.1 , 非常符合邏輯。第二次更新是 JDK 9.0.4 ,不合邏輯。原因是,在 JDK9 的版本計數樣式下,需要留下空白以便應急或不在預期安排的更新使用。但既然沒有更新是必須的,為什麼不簡單稱之為 JDK 9.0.2 呢?

[319]根證書:在 JDK 中將提供一套預設的 CA 根證書。關鍵的安全部件,如 TLS ,在 OpenJDK 構建中將預設有效。這是 Oracle 正在努力確保 OpenJDK 二進位制和 Oracle JDK 二進位制功能上一樣的工作的一部分,是一項有用的補充內容。

 [307] 並行全垃圾回收器 G1 : G1 是設計來作為一種低延時的垃圾回收器(但是如果它跟不上舊的堆碎片產生的提升速率的話,將仍然採用完整壓縮集合)。在 JDK9 之前,預設的收集器是並行,吞吐,收集器。為了減少在使用預設的收集器的應用效能配置檔案的差異,G1 現在有一個並行完整收集機制。

[313]移除 Native-Header 自動生成工具:Java9 開始了一些對 JDK 的家務管理,這項特性是對它的延續。當編譯 JNI 程式碼時,已不再需要單獨的工具來生成頭檔案,因為這可以透過 javac 完成。在未來的某一時刻,JNI 將會被 Panama 專案的結果取代,但是何時發生還不清楚。

[304]垃圾回收器介面: 這不是讓開發者用來控制垃圾回收的介面;而是一個在 JVM 原始碼中的允許另外的垃圾回收器快速方便的整合的介面。

[312]執行緒-區域性變數管控:這是在 JVM 內部相當低階別的更改,現在將允許在不執行全域性虛擬機器安全點的情況下實現執行緒回呼。這將使得停止單個執行緒變得可能和便宜,而不是隻能啟用或停止所有執行緒。

[316]在備用儲存裝置上的堆分配:硬體技術在持續進化,現在可以使用與傳統 DRAM 具有相同介面和類似效能特點的非易失性 RAM 。這項 JEP 將使得 JVM 能夠使用適用於不同型別的儲存機制的堆。

[317] 試驗性的基於 Java 的 JIT 編譯器:最近宣佈的 Metropolis 專案,提議用 Java 重寫大部分 JVM 。乍一想,覺得很奇怪。如果 JVM 是用 Java 編寫的,那麼是否需要一個 JVM 來執行 JVM ? 相應的,這導致了一個很好的映象類比。 現實情況是,使用 Java 編寫 JVM 並不意味著必須將其編譯為位元組碼,你可以使用 AOT 編譯,然後在執行時編譯程式碼以提高效能。這項 JEP 將 Graal 編譯器研究專案引入到 JDK 中。並給將 Metropolis 專案成為現實,使 JVM 效能與當前 C++ 所寫版本匹敵(或有幸超越)提供基礎。

[296]: 合併 JDK 多個程式碼倉庫到一個單獨的儲存庫中:在 JDK9 中,有 8 個倉庫: root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn 。在 JDK10 中這些將被合併為一個,使得跨相互依賴的變更集的儲存庫執行 atomic commit (原子提交)成為可能。

新 API

有 73 項新增內容新增到了標準類庫中。

java.awt.Toolkit

int getMenuShortcutKeyMaskEx(): 確定哪個擴充套件修飾符鍵是選單快捷鍵的適當加速鍵。

java.awt.geom.Path2D:

void trimToSize(): 將此 Path2D 實體的容量計算到它當前的大小。應用可使用此操作將路徑的儲存空間最小化。這個方法也被新增到 Path2D.Double 和 Path2D.Float 類。

java.io.ByteArrayOutputStream:

String toString(Charset): 多載 toString(),透過使用指定的字符集解碼位元組,將緩衝區的內容轉換為字串。

java.io.PrintStream:

lang.io.PrintWriter:

這兩個類都有三個新的建構式,它們需要額外的 Charset 引數。

java.io.Reader:

long transferTo(Writer): 從這個 Reader 中讀取所有字元,並按照所讀的順序將字元寫入給定的 Writer 。

java.lang.Runtime.Version:

有四種新方法傳回新(JEP 322)版本字串欄位的整數值: feature()、interim()、patch() 和 update() 。

java.lang.StackWalker.StackFrame:

String getDescriptor(): 按照 JVM 標準傳回此堆疊幀所代表的方法的描述符。

String getMethodType():傳回此堆疊幀所代表的方法型別,描述引數型別和傳回值型別。

java.lang.invoke.MethodType:

Class > lastParameterType():傳回這個方法型別的最後一個引數型別。如果這個方法型別沒有引數,則傳回空型別作為崗哨值(Sentinel Value)。

java.lang.management.RuntimeMXBean:

long getPid(): R 傳回正在執行的 JVM 的行程 ID 。

java.lang.management.ThreadMXBean:

  • ThreadInfo[] dumpAllThreads(boolean, boolean, int): 傳回所有活動執行緒的執行緒資訊,其中有指定的最大元素數量和同步資訊的堆疊跟蹤。

  • ThreadInfo[] getThreadInfo(long[], boolean, boolean, int): 傳回每個執行緒的執行緒資訊,這些執行緒的標識位於輸入陣列中,其中有指定的最大元素數量和同步資訊的堆疊跟蹤。

java.lang.reflect.MalformedParameterizedTypeException: 添加了一個新的建構式,它以字串的形式作為引數來獲取詳細資訊。

java.net.URLDecoder:

java.net.URLEncoder:

這兩個類都有新的多載的解碼和編碼方法,將 charset 作為附加引數。

java.nio.channels.Channels:

兩個新的靜態多載方法,允許使用 Charset 的 newReader(ReadByteChannel,Charset)和newWriter(WriteByteChannel,Charset)。

java.nio.file.FileStore:

long getBlockSize(): 在這個檔案儲存中傳回每個塊的位元組數。

java.time.chrono: 這個包裡有三個類,HijrahEra、MiinguoEra 和 ThaiBuddhistEra ,都有同樣的方法。

String getDisplayName(TextStyle, Locale): 這將傳回用於識別 era 的文字名稱,適合於向用戶展示。

java.time.format.DateTimeFormatter:

localizedBy(Locale): 傳回指定格式器的一個副本,其中包含地區、日曆、區域、小數和/或時區的本地化值,這將取代該格式器中的值。

java.util: DoubleSummaryStatistics、IntSummaryStatistics 和 LongSummaryStatistics 都有一個新的建構式,它包含 4 個數值。它使用指定的計數、最小值、最大值和總和構造一個非空實體。

java.util.List:

java.util.Map:

java.util.Set: 這些介面中的每一個都增加了一個新的靜態方法,copyOf(Collection)。這些函式按照其迭代順序傳回一個不可修改的串列、對映或包含給定集合的元素的集合。

java.util.Optional:

java.util.OptionalDouble:

java.util.OptionalInt:

java.util.OptionalLong: 每一個類都有一個新的方法,orElseThrow() ,它本質上和 get() 一樣,也就是說,如果 Optional 有值則傳回。否則,將丟擲 NoSuchElementException 。

java.util.Formatter:

java.util.Scanner:

這兩個類都有三個新的建構式,除了其他引數之外,它們都帶有一個 charset 引數。

其它翻譯版本(1)

java.util.Properties: 這有一個新的建構式,它接受一個 int 引數。這將建立一個沒有預設值的空屬性串列,並且指定初始大小以容納指定的元素數量,而無需動態調整大小。還有一個新的多載的 replace 方法,接受三個 Object 引數並傳回一個布林值。只有在當前對映到指定值時,才會替換指定鍵的條目。

java.SplittableRandom:

void nextBytes(byte[]): 用生成的偽隨機位元組填充一個使用者提供的位元組陣列。

java.util.concurrent.FutureTask: 添加了 toString() 方法,該方法傳回一個標識 FutureTask 的字串,以及它的完成狀態。在括號中,狀態包含如下字串中的一個,“Completed Normally” 、“Completed Exceptionally”、 “Cancelled” 或者 “Not completed”。

java.util.concurrent.locks.StampedLock:

  • boolean isLockStamp(long): 傳回一個標記戳表示是否持有一個鎖。

  • boolean isOptimisticReadStamp(long): 傳回一個標記戳代表是否成功的進行了樂觀讀(optimistic read)。

  • boolean isReadLockStamp(long): 傳回一個標記戳表示是否持有一個非獨佔鎖(即 read lock )。

  • boolean isWriteLockStamp(long): 傳回一個標記戳表示是否持有一個獨佔鎖(即 write lock )。

java.jar.JarEntry:

String getRealName(): 傳回這個 JarEntry 的真實名稱。如果這個 JarEntry 是一個多版本 jar 檔案的入口,它被配置為這樣處理,這個方法傳回的名字是 JarEntry 所代表的版本條目的入口,而不是 ZipEntry.getName() 傳回的基本條目的路徑名。如果 JarEntry 不代表一個多版本 jar 檔案的版本化條目或者 jar 檔案沒有被配置為作為一個多版本 jar 檔案進行處理,這個方法將傳回與 ZipEntry.getName() 傳回的相同名稱。

java.util.jar.JarFile:

Stream versionedStream(): 傳回 jar 檔案中指定版本的入口對應 Stream 。與 JarEntry 的 getRealName 方法類似,這與多版本 jar 檔案有關。

java.util.spi.LocaleNameProvider:

getDisplayUnicodeExtensionKey(String, Locale): 為給定的 Unicode 擴充套件鍵傳回一個本地化名稱。

getDisplayUnicodeExtensionType(String, String, Locale): 為給定的 Unicode 擴充套件鍵傳回一個本地化名稱。

java.util.stream.Collectors:

toUnmodifiableList():

toUnmodifiableSet():

toUnmodifiableMap(Function, Function):

toUnmodifiableMap(Function, Function, BinaryOperator): 這四個新方法都傳回 Collectors ,將輸入元素聚集到適當的不可修改的集合中。

java.lang.model.SourceVersion: 現在有了一個欄位,它代表了 JDK 10 的版本。

java.lang.model.util.TypeKindVisitor6:

javax.lang.model.util.TypeKindVisitor9:

(我必須承認,我從來沒聽說過這些類)

R visitNoTypeAsModule(NoType, P): 訪問一個 MODULE 的 pseudo-type 。我不確定為什麼只有這兩個類得到這個方法,因為還有 Visitor7 和 Visitor8 變數。

javax.remote.management.rmi.RMIConnectorServer:

這個類已經添加了兩個欄位: CREDENTIALS_FILTER_PATTERN 和 SERIAL_FILTER_PATTERN 。

javax.ButtonModel:看,Swing 還在更新!

ButtonGroup getGroup(): 傳回按鈕所屬的組。通常用於單選按鈕,它們在組中是互斥的。

javax.plaf.basic.BasicMenuUI:

Dimension getMinimumSize(JComponent): 傳回指定元件適合觀感的最小大小。

JVM 規範改動

這些改動相當小:

  • 4.6節:類檔案格式(第99頁)。在方法訪問標誌方面有小的改動。

  • 4.7節:模組屬性(第169頁)。如果模組不是 java.base ,則 JDK 10 不再允許設定 ACC_TRANSITIVE 或 ACC_STATIC_PHASE 。

  • 4.10節:類檔案的校驗(第252頁)。dup2 指令已改變了 typesafe form 1 的定義,顛倒了 canSafleyPushList 一節中型別的順序(你需要仔細檢視才能發現它)。

  • 5.2節:Java 虛擬機器啟動(第350頁)。該描述添加了在建立初始類或介面時可使用使用者定義的類載入器( bootstrap 類載入器除外)。

對 Java 語言規範的更改

這裡還有一些更改,但主要是為了支援區域性變數型別推斷。

  • 第3.8節:識別符號(第23頁)。在忽略了可忽略的字元之後,識別符號的等價性現在被考慮了。這似乎是合乎邏輯的。

  • (第24頁)一個新的 Token,TypeIdentifier,它支援對區域性變數型別推斷的新用法,而 var 的使用不是關鍵字,而是一個具有特殊含義的識別符號,作為區域性變數宣告的型別。

  • 第4.10.5節:型別預測(第76頁)。這是一個相當複雜的部分,它涉及到捕獲變數、巢狀類以及如何使用區域性變數型別推斷。我建議你閱讀規範中的這一部分,而不是試圖解釋它。

  • 第6.1節:宣告(第134頁)。一個反映使用 TypeIdentifier 來支援區域性變數型別的推斷的小改動。

  • 第6.5節:確定名字的含義(第153頁,第158頁和第159頁)。根據型別識別符號的使用而更改型別別。

  • 第6.5.4.1:簡單的 PackageOrTypeNames(第160頁)

  • 第6.5.4.2節:合規的 PackageOrTypeNames(第160頁)。這兩種方式都與使用 TypeIdentifier 有細微的變化。

  • 第7.5.3:單靜態匯入宣告(第191頁)。這改變了匯入具有相同名稱的靜態型別的規則。除非型別是相同的,否則這將成為一個錯誤,在這種情況下,重覆被忽略。

  • 第7.7.1:依賴(第198頁)。如果你明確宣告一個模組需要 java.base ,那在必要的關鍵字之後,你就不能再使用修飾符(例如靜態)了。

  • 第8部分:正式引數(第244頁)。接收者引數可能只出現在一個實體方法的 formalparameters 串列,或者是一個內部類的建構式中,其中內部類沒有在靜態背景關係中宣告。

  • 第9.7.4節:註釋可能出現的地方(第335頁)。有一個與區域性變數型別推斷相關的變更。

  • 第14.4部分:區域性變數宣告陳述句(第433頁)。實現區域性變數型別推斷所需的大量更改。

  • 第14節:增強的 for 陳述句(第455頁)。這個結構已經更新,包括對區域性變數型別推斷的支援。

  • 第14.20.3節:try-with-resources(474頁)。這個結構已經更新,包括對區域性變數型別推斷的支援。

最後,第 19 章有多處語法更新,反映了應更多使用 TypeIdentifier 型別識別符號,而不僅僅是 Identifier 識別符號,以支援區域性變數型別推斷。

看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

贊(0)

分享創造快樂