Java 10 功能

Java 10是其23年历史中发布的最快版本。Java因其缓慢的增长和演进而受到批评,但Java 10打破了这一概念。Java 10是一个具有许多未来变化的版本,其范围和影响可能不明显,但却深远。在这篇文章中,我们将讨论Java 10版本中新增的各种功能。在此之前,让我们回顾一下引入Java发布模型的一些变化。

长期支持模型

自2017年起,Oracle和Java社区宣布将Java转向新的6个月节奏。它转向了Oracle Java SE产品的长期支持(LTS)模型。这是什么意思? 产品的LTS版本将获得来自Oracle的首要和持续的支持,每3年进行一次定期目标。每个Java版本都是根据一个或两个主要特性建模的,这些特性推动了发布。任何障碍都会推迟发布并使其晚市场。Java 9的主要特性是Project Jigsaw,它推迟了发布日期多次,发布被推迟了1.5年以上。6个月的发布周期将遵循一个发布列车。发布列车将每6个月制定一次计划。符合要求的功能将被加入列车;否则,它们将等待下一次预定的列车。

Oracle JDK vs Open JDK

為了更符合開發者需求,Oracle和Java社區現在將OpenJDK二進制文件作為未來的主要JDK。這是對早期情況的巨大改善,早期的JDK二進制文件是由Oracle專有並許可的,對重新分發有各種限制。然而,Oracle將繼續生產他們的JDK,但僅用於長期支持的版本。這是為了更適應雲和容器,因為OpenJDK二進制文件可以作為容器的一部分進行分發。這意味著什麼? OpenJDK二進制文件將每6個月發布一次,而Oracle JDK二進制文件將每3年發布一次(LTS版本)。採用哪個JDK二進制文件?大型組織需要一些時間來遷移版本;他們會一直使用某個版本直到無法為止。對於Java 6,行業的采納率高於Java 7,然後行業逐漸遷移到Java 8。在我看來,企業最喜歡的將是LTS版本。但是,是Oracle JDK的LTS版本還是OpenJDK的還有待確定,部分原因是雲領域發生了很多變化。Java 9和10是非LTS版本。預計將於2018年9月發布的Java 11將是一個LTS版本。

Java 10 功能

讓我們來一睹 Java 10 中的功能。

  1. 基於時間的版本命名(JEP 322)

根据时间发布周期的采纳,Oracle修改了Java SE平台和JDK的版本字符串方案,以及相关的版本信息,适用于当前和未来的时间发布模型。版本号的新模式为:$FEATURE.$INTERIM.$UPDATE.$PATCH $FEATURE:计数器每6个月递增一次,并基于功能发布版本,例如:JDK 10,JDK 11。 $INTERIM:计数器将为不包含不兼容更改的兼容性错误修复和增强功能的非功能发布递增。通常情况下,这将为零,因为在六个月的期间内不会有中间发布。这是为将来对发布模型的修订而保留的。 $UPDATE:计数器将为修复安全问题、回归和新功能中的错误的兼容性更新发布递增。这是在功能发布后一个月以及以后每3个月更新一次。2018年4月发布的是JDK 10.0.1,7月发布的是JDK 10.0.2,依此类推 $PATCH:计数器将为紧急发布以修复关键问题递增。新的API已添加以通过编程方式获取这些计数值。让我们来看一下;

Version version = Runtime.version();
version.feature();
version.interim();
version.update();
version.patch();

现在,让我们来看一下返回版本信息的Java启动器:

$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)

版本号格式为“10”,因为没有其他计数器不为零。发布日期被添加了进去。18.3可以解读为2018年第3个月,构建10+46表示版本10的第46个构建。对于JDK 10.0.1的假设构建93,构建将是10.0.1+939。### 本地变量类型推断(JEP 286)

局部變量類型推斷是Java 10中開發人員最重要的新功能。它為具有初始化程序的局部變量聲明添加了類型推斷。局部類型推斷僅適用於以下情景:

  • 僅限於具有初始化程序的局部變量
  • 增強型for循環的索引或索引
  • 在for循環中聲明的局部變量

讓我們來看一下它的用法:

var numbers = List.of(1, 2, 3, 4, 5); // inferred value ArrayList
// 增強型for循環的索引
for (var number : numbers) {
	System.out.println(number);
}
// 在循環中聲明的局部變量
for (var i = 0; i < numbers.size(); i++) {
	System.out.println(numbers.get(i));
}

您可以在我們的獨家文章“java 10局部變量類型推斷”中了解更多信息。java 10局部變量類型推斷。13. ### 實驗性基於Java的JIT編譯器(JEP 317)

此功能使得基於 Java 的 JIT 編譯器 Graal 可以在 Linux/x64 平台上作為實驗性 JIT 編譯器使用。這無疑是 Java 10 功能列表中最具未來感的一項。Graal 在 Java 9 中被引入。它是 JIT 編譯器的另一種選擇,我們一直以來都在使用。它是 JVM 的插件,這意味著 JIT 編譯器不與 JVM 綁定,可以動態地插入並替換為符合 JVMCI(Java-Level JVM Compiler Interface)的任何其他插件。它還為 Java 世界帶來了 Ahead of Time(AOT)編譯。它還支持多語言解釋。”基於 Java 的及時編譯器,用於將 Java 字節碼轉換為機器碼。”這樣說明會不會令人困惑?如果 JVM 是用 Java 編寫的,那麼你不是需要一個 JVM 來運行 JVM 嗎?JVM 可以編譯為 AOT,然後 JIT 編譯器可以在其中使用以通過即時代碼優化提高性能。Graal 是用 Java 從頭開始完全重寫的 JIT 編譯器。先前的 JIT 編譯器是用 C++ 編寫的。對於任何編程語言來說,它被認為是最後一個演化階段之一。您可以使用以下 JVM 參數切換到 Graal:

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

您可以從 Chris Seaton 的演示了解更多有關 Graal 的信息。

這個功能有助於改善啟動時的足跡,將現有的類別資料共享(“CDS”)功能擴展,以允許將應用程式類別放置在共享存檔中。 JVM 在啟動時執行一些初步步驟,其中之一是將類別加載到內存中。 如果有多個包含多個類別的 JAR 檔,則在第一個請求中的延遲顯而易見。 這在無伺服器架構中成為一個問題,其中啟動時間至關重要。 為了降低應用程式啟動時間,可以使用應用程式類別資料共享。 想法是通過在不同的 Java 進程之間共享共同的類別元數據來減少足跡。 可以通過以下 3 個步驟來實現這一目標: 確定要存檔的類別:使用 java 啟動器創建要存檔的文件列表,可以通過以下參數實現:

$java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst -cp hello.jar HelloWorld

創建 AppCDS 存檔:使用 java 啟動器來創建用於應用程式 CDS 的文件列表的存檔,可以通過以下參數實現:

$java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar

使用 AppCDS 存檔:使用以下參數的 Java 啟動器來使用應用程式 CDS。

$java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
  1. 用於 G1 的平行完整 GC(JEP 307)

G1垃圾收集器在JDK 9中成為默認。 G1垃圾收集器避免了任何完整的垃圾收集,但是當用於收集的並行線程無法快速恢復內存時,用戶的體驗就會受到影響。此更改通過使完整的GC並行來改進G1最壞情況的延遲。G1收集器的標記-掃描-壓縮算法作為此更改的一部分進行了並行化,當用於收集的並行線程無法快速恢復內存時將被觸發。垃圾收集器25. ### 垃圾收集器介面(JEP 304)

這項JEP是一項具有前瞻性的變更。通過引入共同的垃圾收集器介面,它提高了不同垃圾收集器的代碼隔離性。此更改為內部GC代碼提供了更好的模塊化。這將有助於將來添加新的GC而無需更改現有的代碼庫,還有助於刪除或維護以前的GC。26. ### 額外的Unicode語言標籤擴展(JEP 314)

此功能增強了java.util.Locale和相關API以實現BCP 47語言標籤的額外Unicode擴展。截至Java SE 9,支持的BCP 47 U語言標籤擴展是“ca”和“nu”。此JEP將添加對以下額外擴展的支持:

  • cu(貨幣類型)
  • fw(每週的第一天)
  • rg(區域覆蓋)
  • 時區(time zone)

為了支援這些額外的擴展,對各種API進行了更改,以提供基於U或其他擴展的資訊。

java.text.DateFormat::get*Instance
java.text.DateFormatSymbols::getInstance
java.text.DecimalFormatSymbols::getInstance
java.text.NumberFormat::get*Instance
java.time.format.DateTimeFormatter::localizedBy
java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern
java.time.format.DecimalStyle::of
java.time.temporal.WeekFields::of
java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}
java.util.Currency::getInstance
java.util.Locale::getDisplayName
java.util.spi.LocaleNameProvider
  1. 根憑證(JEP 319)

為了推廣OpenJDK並使其對社區使用者更具吸引力,此功能在JDK中提供了一組預設的根憑證機構(CA)證書。這也意味著Oracle和OpenJDK二進位文件在功能上將完全相同。重要的安全組件(例如TLS)將在未來的OpenJDK版本中默認運行。30. ### 纏繞式本地握手(JEP 312)

這是一個內部JVM功能,旨在提高性能。握手操作是在JavaThread處於安全點狀態時為每個JavaThread執行的回調。回調由線程本身執行,或者在保持線程處於阻塞狀態時由VM線程執行。此功能提供了一種在執行緒上執行回調的方式,而無需執行全局VM安全點。使得停止單個線程而不僅僅是所有線程或無線程變得可能且廉價。31. ### 在替代記憶體設備上進行堆分配(JEP 316)

應用程序變得對內存要求更高,雲原生應用程序、內存數據庫和流應用程序的增加。為了滿足這些服務的需求,有各種內存架構可用。此功能增強了HotSpot VM的功能,使其能夠在用戶指定的替代內存設備上分配Java對象堆,例如NV-DIMM。該JEP針對具有DRAM相同語義的替代內存設備,包括原子操作的語義,因此可以在對象堆中替代DRAM而無需更改現有應用程序代碼。32. ### 刪除本地標頭生成工具 – javah(JEP 313)

這是一個清理變更,從JDK中刪除javah工具。該工具功能已添加到JDK 8的javac中,允許在編譯時編寫本地標頭文件,使javah變得無用。35. ### 將JDK Forest整合為單一存儲庫(JEP 296)

多年來,JDK代碼庫中存在各種Mercurial存儲庫。不同的存儲庫確實提供了一些優勢,但它們也有各種運營缺陷。作為這一變更的一部分,JDK森林的眾多存儲庫被合併為一個單一存儲庫,以簡化和優化開發。36. ### API更改

Java 10已經新增並刪除(是的,這不是打錯字)API。 Java 9引入了增強的棄用標記,其中某些API被標記為將在未來版本中刪除。已刪除的API:您可以在這裡找到已刪除的API。 新增的API:在Java 10中新增了73個新的API。您可以在這裡找到新增的API,以及相應的比較。讓我們看一下其中一些新增:

  • 新增了List、Map和Set介面,具有靜態的copyOf(Collection)方法。它返回一個包含提供的條目的不可修改的List、Map或Set。對於List,如果後續修改了給定的List,返回的List將不反映這些修改。
  • Optional及其基本變體獲得了一個名為orElseThrow()的方法。這與get()完全相同,但Java文檔指出它是get()的首選替代方法。
  • Collectors類獲得了各種方法,用於收集不可修改的集合(Set、List、Map)。
List actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors); // prints [Jack Nicholson, Marlon Brando]
//新增的API - 由List創建一個不可修改的List。
List copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro");將生成
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors); // prints [Jack Nicholson, Marlon Brando]
		
String str = "";
Optional name = Optional.ofNullable(str);
//新增的API - 是get()方法的首選選項
name.orElseThrow(); // same as name.get()  

//新增的API - Collectors.toUnmodifiableList
List collect = actors.stream().collect(Collectors.toUnmodifiableList());
// collect.add("Tom Hanks"); //將生成
// UnsupportedOperationException

結論

在這篇文章中,我們介紹了Java 10的不同新功能添加。如果您認為這裡漏掉了任何重要內容,請通過評論讓我們知道。通常情況下,您可以在GitHub 這裡檢查完整的代碼。

Source:
https://www.digitalocean.com/community/tutorials/java-10-features