Java7~Java17 新特性
Java7~Java17 新特性
Java7
2011-07-28
長期支援版本,支援到2020年6月
型別推斷 (鑽石操作符Diamond Operator )
// 之前版本
Map<String,List<String>> anagrams = new HashMap<String,List<String>>();
// jdk7
Map<String,List<String>> anagrams = new HashMap<>();
注:這個<>被叫做diamond(鑽石)運算子,Java 7後這個運算子從引用的宣告中推斷型別。
在switch語句中使用字串
public voidprocessTrade(Trade t) {
String status = t.getStatus();
switch(status) {
caseNEW:
newTrade(t);
break;
caseEXECUTE:
executeTrade(t);
break;
casePENDING:
pendingTrade(t);
break;
default:
break;
}
}
自動資源管理 try-with-resources
帶下劃線的數字文字
int thousand = 1_000;
int million = 1_000_000
注:這個版本中也引入了二進位制文字-例如“0b1”,因此不必再將它們轉換為十六進位制。
改進的異常處理
public voidnewMultiCatch() {
try{
methodThatThrowsThreeExceptions();
} catch(ExceptionOne | ExceptionTwo | ExceptionThree e) {
// log and deal with all Exceptions
}
}
New file system API(NIO 2.0)
新的java.nio.file由包和介面組成例如:Path,Paths,FileSystem,FileSystems等等。
檔案更改通知:當檔案發生更改的時候,能及時作出反饋,WatchServiceAPI 允許您在對主題(目錄或檔案)進行更改時接收通知事件。
Fork/Join框架
Fork/Join
並行演算法是我們所熟悉的分治演算法的並行版本,典型的用法如下:
// 虛擬碼
Result solve(Problem problem) {
if (problem is small) {
directly solve problem
} else {
split problem into independent parts
fork new subtasks to solve each part
join all subtasks
compose result from subresults
}
}
Java8
2014-03-18
長期支援版本,支援到2030年12月
Lambda 表示式
Lambda 允許把函式作為一個方法的引數(函式作為引數傳遞到方法中)
// 1. 不需要引數,返回值為 5
() -> 5
// 2. 接收一個引數(數字型別),返回其2倍的值
x -> 2 * x
// 3. 接受2個引數(數字),並返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 物件,並在控制檯列印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)
方法引用
方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
預設方法
預設方法就是一個在接口裡面有了一個實現的方法。
首先,之前的介面是個雙刃劍,好處是面向抽象而不是面向具體程式設計,缺陷是,當需要修改介面時候,需要修改全部實現該介面的類,目前的 java 8 之前的集合框架沒有 foreach 方法,通常能想到的解決辦法是在JDK裡給相關的介面新增新的方法及實現。然而,對於已經發布的版本,是沒法在給介面新增新方法的同時不影響已有的實現。所以引進的預設方法。他們的目的是為了解決介面的修改與現有的實現不相容的問題。
public interface Vehicle {
default void print(){
System.out.println("我是一輛車!");
}
}
Stream API
新新增的Stream API(java.util.stream) 把真正的函數語言程式設計風格引入到Java中。
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
List<Integer> transactionsIds =
widgets.stream()
.filter(b -> b.getColor() == RED)
.sorted((x,y) -> x.getWeight() - y.getWeight())
.mapToInt(Widget::getWeight)
.sum();
Date Time API
加強對日期與時間的處理,新的java.time包涵蓋了所有處理日期,時間,日期/時間,時區,時刻(instants),過程(during)與時鐘(clock)的操作。
// 獲取當前的日期時間
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("當前時間: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("date1: " + date1);
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date2: " + date2);
// 12 december 2014
LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
System.out.println("date3: " + date3);
// 22 小時 15 分鐘
LocalTime date4 = LocalTime.of(22, 15);
System.out.println("date4: " + date4);
// 解析字串
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date5: " + date5);
Optional 類
Optional 類已經成為 Java 8 類庫的一部分,用來解決空指標異常。
String username = Optional.ofNullable(user).map(x->x.getUsername).orElse('clive');
Nashorn, JavaScript 引擎
Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上執行特定的javascript應用。
jjs sample.js
Base64
- 基本:輸出被對映到一組字元
A-Za-z0-9+/
,編碼不新增任何行標,輸出的解碼僅支援A-Za-z0-9+/
。 - URL:輸出對映到一組字元
A-Za-z0-9+_
,輸出是URL和檔案。 - MIME:輸出隱射到MIME友好格式。輸出每行不超過76字元,並且使用'\r'並跟隨'\n'作為分割。編碼輸出最後沒有行分割。
// 編碼
String base64encodedString = Base64.getEncoder().encodeToString("java8".getBytes("utf-8"));
// 解碼
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
Java9
2017-09
模組系統
模組是一個包的容器,Java 9 最大的變化之一是引入了模組系統(Jigsaw 專案)。塊就是程式碼和資料的封裝體。模組的程式碼被組織成多個包,每個包中包含Java類和介面;模組的資料則包括資原始檔和其他靜態資訊。
module-info.java
module cn.cliveyuan.mymodule {
}
REPL (JShell)
互動式程式設計環境。JShell 是 Java 9 新增的一個互動式的程式設計環境工具。它允許你無需使用類或者方法包裝來執行 Java 語句。它與 Python 的直譯器類似,可以直接 輸入表示式並檢視其執行結果。
jshell> int doubled(int i){ return i*2;}
| created method doubled(int)
jshell> doubled(6)
$3 ==> 12
jshell>
HTTP 2 客戶端
HTTP/2標準是HTTP協議的最新版本,新的 HTTPClient API 支援 WebSocket 和 HTTP2 流以及伺服器推送特性。
改進的 Javadoc
Javadoc 現在支援在 API 文件中的進行搜尋。另外,Javadoc 的輸出現在符合相容 HTML5 標準。
多版本相容 JAR 包
多版本相容 JAR 功能能讓你建立僅在特定版本的 Java 環境中執行庫程式時選擇使用的 class 版本。
然後 META-INF 目錄下還新增了一個 versions 目錄,如果是要支援 java9,則在 versions 目錄下有 9 的目錄。
multirelease.jar
├── META-INF
│ └── versions
│ └── 9
│ └── multirelease
│ └── Helper.class
├── multirelease
├── Helper.class
└── Main.class
集合工廠方法
List,Set 和 Map 介面中,新的靜態工廠方法可以建立這些集合的不可變例項。
static <E> List<E> of(E e1, E e2, E e3);
static <E> Set<E> of(E e1, E e2, E e3);
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3);
static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
私有介面方法
在介面中使用private私有方法。我們可以使用 private 訪問修飾符在介面中編寫私有方法。
介面中可定義:
- 常量
- 抽象方法
- 預設方法
- 靜態方法
- 私有方法
- 私有靜態方法
interface Logging {
String ORACLE = "Oracle_Database";
String MYSQL = "MySql_Database";
private void log(String message, String prefix) {
System.out.println("Log Message : " + prefix);
}
default void logInfo(String message) {
log(message, "INFO");
}
}
程序 API
改進的 API 來控制和管理作業系統程序。引進 java.lang.ProcessHandle 及其巢狀介面 Info ### 來讓開發者逃離時常因為要獲取一個本地程序的 PID 而不得不使用原生代碼的窘境。
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
String np = "Not Present";
Process p = pb.start();
ProcessHandle.Info info = p.info();
System.out.printf("Process ID : %s%n", p.pid());
System.out.printf("Command name : %s%n", info.command().orElse(np));
System.out.printf("Command line : %s%n", info.commandLine().orElse(np));
System.out.printf("Start time: %s%n",
info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
.toLocalDateTime().toString()).orElse(np));
System.out.printf("Arguments : %s%n",
info.arguments().map(a -> Stream.of(a).collect(
Collectors.joining(" "))).orElse(np));
System.out.printf("User : %s%n", info.user().orElse(np));
改進的 Stream API
改進的 Stream API 添加了一些便利的方法,使流處理更容易,並使用收集器編寫複雜的查詢。
Java 9 為 Stream 新增了幾個方法:dropWhile、takeWhile、ofNullable,為 iterate 方法新增了一個過載方法。
改進 try-with-resources
如果你已經有一個資源是 final 或等效於 final 變數,您可以在 try-with-resources ### 語句中使用該變數,而無需在 try-with-resources 語句中宣告一個新變數。
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
.forEach(System.out::print);
// output: abc
Stream.of("a","b","c","","e","f").dropWhile(s-> !s.isEmpty())
.forEach(System.out::print);
// output: ef
IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::println);
// output: 3 \n 6 \n 9
// aka: for(int i = 3; i < 10; i +=3) {}
Stream.ofNullable(null).count()
改進的棄用註解 @Deprecated
註解 @Deprecated 可以標記 Java API 狀態,可以表示被標記的 API 將會被移除,或者已經破壞。
Java 9 中註解增加了兩個新元素:since和forRemoval。
- since: 元素指定已註解的API元素已被棄用的版本。
- forRemoval: 元素表示註解的 API 元素在將來的版本中被刪除,應該遷移 API。
改進鑽石操作符(Diamond Operator)
匿名類可以使用鑽石操作符(Diamond Operator)。
// before java 9
List<Integer> list = new ArrayList<Integer>(){{
add(1);
}};
// java 9
List<Integer> list = new ArrayList<>(){{
add(1);
}};
改進 Optional 類
java.util.Optional 添加了很多新的有用方法,Optional 可以直接轉為 stream。
- stream()將 Optional 轉為一個 Stream,如果該 Optional 中包含值,那麼就返回包含這個值的 Stream,否則返回一個空的 Stream(Stream.empty())。
- ifPresentOrElse()如果一個 Optional 包含值,則對其包含的值呼叫函式 action,如果 Optional 不包含值,那麼 ifPresentOrElse 便會呼叫 emptyAction,即 emptyAction.run()。
- or()如果值存在,返回 Optional 指定的值,否則返回一個預設的值。
多解析度影象 API
定義多解析度影象API,開發者可以很容易的操作和展示不同解析度的影象了。
改進的 CompletableFuture API
CompletableFuture 類的非同步機制可以在 ProcessHandle.onExit 方法退出時執行操作。
- 支援 delays 和 timeouts
- 提升了對子類化的支援
- 新的工廠方法
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
public <U> CompletableFuture<U> newIncompleteFuture()
響應式流(Reactive Streams) API
Java 9中引入了新的響應式流 API 來支援 Java 9 中的響應式程式設計。
- Publisher提供無邊界的資料序列,可以依據訂閱者要求釋出給訂閱者。
- Subscriber訂閱資料和獲得訊息,需要實現訂閱通知,資料通知,出錯處理,完成處理。
- Subscription代表一個訂閱,繫結訂閱者和釋出者,訂閱者可以對訂閱做控制(請求傳送和取消)。
- Processor處理器,即是個訂閱者又是個釋出者,內部對資料進行處理後再次釋出。
CompletableFuture<Void> subTask;
try (SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>()) {
subTask = publisher.consume(System.out::print);
IntStream.rangeClosed(1, 3).forEach(publisher::submit);
}
subTask.join();
Java10
2018-03-21
區域性變數的型別推斷
Java開始引用像指令碼語言JavaScript中的var型別(弱型別),允許你通過var定義任何型別的變數。
var varList = new ArrayList<String>();
// aka
ArrayList<String> varList = new ArrayList<String>();
應用類資料共享(CDS)
CDS 在 JDK5 時被引進以改善 JVM 啟動的表現,同時減少當多個虛擬機器在同一個物理或虛擬的機器上執行時的資源佔用。JDK10 將擴充套件 CDS 到允許內部系統的類載入器、內部平臺的類載入器和自定義類載入器來載入獲得的類。之前,CDS 的使用僅僅限制在了 bootstrap 的類載入器。
額外的 Unicode 語言標籤擴充套件
這將改善 java.util.Locale 類和相關的 API 以實現額外 BCP47 語言標籤的 Unicode 擴充套件。尤其是,貨幣型別,一週的第一天,區域覆蓋和時區等標籤現在將被支援。
基於時間的版本控制
從Java 10開始,採用了一種新的嚴格的基於時間的釋出模式。 在這個新模型中,Java平臺的主要版本(現稱為功能版本)將每6個月(3月和9月)釋出一次。
根證書
在 JDK 中將提供一套預設的 CA 根證書。關鍵的安全部件,如 TLS ,在 OpenJDK 構建中將預設有效。這是 Oracle 正在努力確保 OpenJDK 二進位制和 Oracle JDK 二進位制功能上一樣的工作的一部分,是一項有用的補充內容。
並行全垃圾回收器 G1
G1 是設計來作為一種低延時的垃圾回收器(但是如果它跟不上舊的堆碎片產生的提升速率的話,將仍然採用完整壓縮集合)。在 JDK9 之前,預設的收集器是並行,吞吐,收集器。為了減少在使用預設的收集器的應用效能配置檔案的差異,G1 現在有一個並行完整收集機制。
垃圾回收器介面
這不是讓開發者用來控制垃圾回收的介面;而是一個在 JVM 原始碼中的允許另外的垃圾回收器快速方便的整合的介面。
移除 Native-Header 自動生成工具 (javah)
當編譯 JNI 程式碼時,已不再需要單獨的工具來生成標頭檔案,因為這可以通過 javac 完成。
javac -h xxx
執行緒-區域性變數管控
這是在 JVM 內部相當低級別的更改,現在將允許在不執行全域性虛擬機器安全點的情況下實現執行緒回撥。這將使得停止單個執行緒變得可能和便宜,而不是隻能啟用或停止所有執行緒。
在備用儲存裝置上的堆分配
硬體技術在持續進化,現在可以使用與傳統 DRAM 具有相同介面和類似效能特點的非易失性 RAM 。這項 JEP 將使得 JVM 能夠使用適用於不同型別的儲存機制的堆。
試驗性的基於 Java 的 JIT 編譯器
最近宣佈的 Metropolis 專案,提議用 Java 重寫大部分 JVM 。乍一想,覺得很奇怪。如果 JVM 是用 Java 編寫的,那麼是否需要一個 JVM 來執行 JVM ? 相應的,這導致了一個很好的映象類比。 現實情況是,使用 Java 編寫 JVM 並不意味著必須將其編譯為位元組碼,你可以使用 AOT 編譯,然後在執行時編譯程式碼以提高效能。
這項 JEP 將 Graal 編譯器研究專案引入到 JDK 中。並給將 Metropolis 專案成為現實,使 JVM 效能與當前 C++ 所寫版本匹敵(或有幸超越)提供基礎。
合併 JDK 多個程式碼倉庫到一個單獨的儲存庫中
在 JDK9 中,有 8 個倉庫: root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn 。在 JDK10 中這些將被合併為一個,使得跨相互依賴的變更集的儲存庫執行 atomic commit (原子提交)成為可能。
Java11
2018-09-25
長期支援版本,支援到2026年9月
字串增強
Java 11 增加了一系列的字串處理方法
// 判斷字串是否為空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack", 原來的trim()不能去除Unicode格式的空白
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 複製字串
"Java".repeat(3);// "JavaJavaJava"
// 行數統計
"A\nB\nC".lines().count(); // 3 根據回車符分隔
集合增強
var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
Optional增強
Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack
HTTP Client API
var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 非同步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
一個命令編譯執行原始碼
java Javastack.java
垃圾收集器GC
- 新增Epsilon
- 新增ZGC
- G1增強
Java12
2019-03-19
String API 更改
// 縮排:字串前增加空格
String result = "foo\nbar\nbar2".indent(4);
// 轉換:Function型別作為入參時,內部的「處理邏輯」將增加更多靈活性
String transformedName = name.transform(String::strip);
// 比較檔案內容: 如果內容相同返回-1,否則返回第一處不匹配的位元組位置
long mismatch = Files.mismatch(Path, Path);
緊湊的資料格式
緊湊的數字表示更易於閱讀,並且在不丟失原始含義的情況下,在螢幕上需要更少的空間。
NumberFormat formatter = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String formattedString = formatter.format(25000L);
System.out.println(formattedString);
// output: 25K
Switch表示式(預覽)
注意:要使用此預覽特性,請記住,我們必須在應用程式啟動期間使用-enable-preview標誌顯式地指示JVM。
boolean isWeekend = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> false;
case SATURDAY, SUNDAY -> true;
default -> throw new IllegalStateException("Illegal day entry :: " + day);
};
System.out.println(isWeekend);
低暫停時間的GC (Shenandoah GC)
Shenandoah是一種垃圾收集(GC)演算法,旨在保證低延遲(10 - 500 ms的下限)。 它通過在執行Java工作執行緒的同時執行GC操作減少GC暫停時間。 使用Shenandoah,暫停時間不依賴於堆的大小。 這意味著無論堆的大小如何,暫停時間都是差不多的。
這是一個實驗性功能,不包含在預設(Oracle)的OpenJDK版本中。
微基準測試套件 (JMH)
此功能為JDK原始碼添加了一套微基準測試(大約100個),簡化了現有微基準測試的執行和新基準測試的建立過程。 它基於Java Microbenchmark Harness(JMH)並支援JMH更新。
此功能使開發人員可以輕鬆運行當前的微基準測試併為JDK原始碼新增新的微基準測試。 可以基於Java Microbenchmark Harness(JMH)輕鬆測試JDK效能。 它將支援JMH更新,並在套件中包含一組(約100個)基準測試。
JVM常量API
JEP 334引入了一個API,用於建模關鍵類檔案和執行時artifacts,例如常量池。 此API將包括ClassDesc,MethodTypeDesc,MethodHandleDesc和DynamicConstantDesc等類。此 API 對於操作類和方法的工具很有幫助。
只保留一個AArch64實現
Java 12將只有一個ARM 64位實現(aarch64)。 目標是刪除所有與arm64實現相關的程式碼,同時保留32位ARM埠和64位aarch64實現。這將把重點轉移到單個64位ARM實現,並消除維護兩個實現所需的重複工作。 當前的JDK 11實現中有兩個64位ARM實現。
預設類資料共享歸檔檔案
通過在64位平臺上的預設類列表的幫助下生成CDS歸檔來改進JDK構建過程,從而有效地消除了執行java -Xshare:dump
。
此功能的目標包括:1.改進開箱即用的啟動時間; 2. 擺脫使用-Xshare:dump
。
可中止的G1 Mixed GC
此功能通過將Mixed GC集拆分為強制部分和可選部分,使G1垃圾收集器更有效地中止垃圾收集過程。通過允許垃圾收集過程優先處理強制集,g1可以更多滿足滿足暫停時間目標。
G1及時返回未使用的已分配記憶體
此功能的主要目標是改進G1垃圾收集器,以便在不活動時將Java堆記憶體歸還給作業系統。 為實現此目標,G1將在低應用程式活動期間定期生成或持續迴圈檢查完整的Java堆使用情況。這將立即歸還未使用的部分Java堆記憶體給作業系統。 使用者可以選擇執行FULL GC以最大化返回的記憶體量。
Support for Unicode 11
Unicode 11增加了684個字元,共137,374個字元,增加了7個新指令碼,共146個指令碼。
Java13
2019-09-17
Switch表示式 (Beta版)
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
文字塊 Text Blocks(預覽版)
// before
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
// now
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";
Dynamic CDS Archives
擴充套件CDS,從而允許在Java應用執行後進行動態類歸檔,歸檔的類將包括當前預設基礎CDS歸檔中不存在的應用類和庫中的類。
主要目標有:
- 提高CDS的可用性,消除了使用者使用時為每個應用程式建立類列表(class list)的需要;
- 通過
-Xshare:dump
引數開啟靜態歸檔,包括內建的類載入器和使用者自定義的類載入器。
ZGC: Uncommit Unused Memory
增強ZGC特性,將沒有使用的堆記憶體歸還給作業系統。ZGC當前不能把記憶體歸還給作業系統,即使是那些很久都沒有使用的記憶體,有點像貔貅一樣,只進不出,哈哈。這種行為並不是對任何應用和環境都是友好的,尤其是那些記憶體佔用敏感的服務。
Reimplement the Legacy Socket API
用一個易於維護和Debug的,更簡單、更現代的實現來取代java.net.Socket和java.net.ServerSocket。Socket和ServerSocket可以追溯到JDK1.0,它們的實現混合了Java和C程式碼,維護和除錯都非常痛苦。而且其實現用執行緒棧來進行IO buffer,導致某些場景需要調大Xss。
全新實現的NioSocketImpl,用來取代PlainSocketImpl,它的優點如下:
- 非常容易維護和Debug;
- 直接使用JDK的NIO實現,不需要自己的原生代碼;
- 結合了buffer cache機制,所以不需要用執行緒棧來進行IO操作;
- 用JUC的鎖取代synchronized修飾的方法;
Java14
2020-03-17
instanceof模式匹配(預覽版)
對instanceof
進行改進,由原來的檢查物件型別變成了先對物件進行型別匹配,校驗成功之後轉換成對應型別,然後再複製給區域性變數,並且只有當模式匹配表示式匹配成功才會生效和複製,區域性變數只能在當前程式碼塊使用。
if (person instanceof Student student) {
student.say();
// other student operations
} else if (person instanceof Teacher teacher) {
teacher.say();
// other teacher operations
}
Record型別(預覽版)
Java14引入了record型別支援更加緊湊的方式去宣告一個類,而這些類能夠作為不可變資料型別的封裝持有者。
public class TestPros {
public static void main(String[] args) {
}
public record person(String name, int age) {
public String getName() {
return this.name;
}
public int getAge() {
return age;
}
}
}
Java14引入了record類,所以在java.lang.Class引入了2個新方法
RecordComponent[] getRecordComponents()
boolean isRecord()
Switch表示式 (正式版)
- 需要保持與之前
switch
語句同樣的case
分支情況 - 使用
yield
關鍵字來返回case
分支需在Java14
表示式中,表示式預設執行完之後自動跳出,不會繼續往後執行要返回的結果 switch
表示式中不再需要顯式地使用return,break
或者continue
來跳出當前分支- 在
Java14
表示式中,表示式預設執行完之後自動跳出,不會繼續往後執行 - 相同的
case
方法塊,可以將case
條件並列
int number = switch (day) {
case 1, 2, 3 -> 10;
case 5 -> 5;
default -> 0;
};
改進NullPointExceptions
提示資訊
改進空指標提示資訊 幫助我們更加直觀找到 Null變數
public static void main(String[] args) {
String str = null;
System.out.println(str.length());
}
//Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
at cn.cliveyuan.TestPros.main(TestPros.java:7)
G1的NUMA可識別記憶體分配
- 改進非一致性系統記憶體訪問的G1垃圾收集器整體效能,主要針對年輕代記憶體分配優化.
- 建立新物件->分配記憶體->存放記憶體(region)->(支援NUMA)分配當前執行緒NUMA節點空閒記憶體區。基於同一個物件建立呼叫頻率較高,存活時間短(能夠提高一些大型計算機的G1記憶體分配回收效能)
- 啟動可識別記憶體分配
-XX:+UseNUMA
刪除CMS垃圾回收器
Java14 正式移除了CMS垃圾回收器
ZGC支援MacOS和Windows系統 (實驗階段)
Java14在之前的Linux/x64增加了MacOS和windows系統,解決了開發人員你需要在桌面作業系統中使用ZGC問題。在MacOS和Windows下面開啟ZGC的方式需要使用vm引數
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
啟用ParallelScavenge和SeialOld GC的組合使用
年輕代當中使用並行演算法、老年代使用序列演算法,混搭使用,太過冒險。所以Java14考慮將這兩GC的組合啟用 採用如下引數 去棄用該組合引數
-XX:+UseParallelGC -XX:-UseParallelOldGC
文字塊 (第二預覽版本)
- Java14 在13的基礎上新增了 兩個轉義符 “\”和“\s"
\行終止符
\s 表示一個空格
stripIndent()
:用於從文字塊中去除空白字元translateEscapes()
:用於翻譯轉義字元formatted(Object... args)
:用於格式化
Java15
2020-09-15
EdDSA 數字簽名演算法
新加入 Edwards-Curve 數字簽名演算法(EdDSA)實現加密簽名。在許多其它加密庫(如 OpenSSL 和 BoringSSL)中得到支援。與 JDK 中的現有簽名方案相比,EdDSA 具有更高的安全性和效能。
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();
// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
封閉類(預覽版)
可以是封閉類和或者封閉介面,用來增強 Java 程式語言,防止其他類或介面擴充套件或實現它們。有了這個特性,意味著以後不是你想繼承就繼承,想實現就實現了,你得經過允許才行。
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
// 類 Student 被 sealed 修飾,說明它是一個封閉類,並且只允許指定的 3 個子類繼承。
隱藏類
此功能可幫助需要在執行時生成類的框架。框架生成類需要動態擴充套件其行為,但是又希望限制對這些類的訪問。隱藏類很有用,因為它們只能通過反射訪問,而不能從普通位元組碼訪問。此外,隱藏類可以獨立於其他類載入,這可以減少框架的記憶體佔用。這是一個新的功能。
移除了 Nashorn JavaScript 指令碼引擎
移除了 Nashorn JavaScript 指令碼引擎、APIs,以及 jjs 工具。這些早在 JDK 11 中就已經被標記為 deprecated 了,JDK 15 被移除就很正常了。Nashorn 是 JDK 1.8 引入的一個 JavaScript 指令碼引擎,用來取代 Rhino 指令碼引擎。Nashorn 是 ECMAScript-262 5.1 的完整實現,增強了 Java 和 JavaScript 的相容性,並且大大提升了效能。那麼為什麼要移除?官方的解釋是主要的:隨著 ECMAScript 指令碼語言的結構、API 的改編速度越來越快,維護 Nashorn 太有挑戰性了,所以移除。
重新實現 DatagramSocket API
重新實現舊版 DatagramSocket API,更簡單、更現代的實現來代替java.net.DatagramSocket和java.net.MulticastSocketAPI 的基礎實現,提高了 JDK 的可維護性和穩定性。新的底層實現將很容易使用虛擬執行緒,目前正在 Loom 專案中進行探索。這也是 JEP 353 的後續更新版本,JEP 353 已經重新實現了 Socket API。
準備禁用和廢除偏向鎖
在 JDK 15 中,預設情況下禁用偏向鎖(Biased Locking),並棄用所有相關的命令列選項。後面再確定是否需要繼續支援偏向鎖,因為維護這種鎖同步優化的成本太高了。
模式匹配(第二次預覽)
第一次預覽是 JDK 14 中提出來的
// before
if (obj instanceof String) {
String s = (String) obj;
// 使用s
}
// now
if (obj instanceof String s) {
// 使用s
}
ZGC 功能轉正
ZGC是一個可伸縮、低延遲的垃圾回收器。ZGC 已由JEP 333整合到JDK 11 中,其目標是通過減少 GC 停頓時間來提高效能。藉助 JEP 377,JDK 15 將 ZGC 垃圾收集器從預覽特性變更為正式特性而已,沒錯,轉正了。這個 JEP 不會更改預設的 GC,預設仍然是 G1。
文字塊 (正式版)
文字塊,是一個多行字串,它可以避免使用大多數轉義符號,自動以可預測的方式格式化字串,並讓開發人員在需要時可以控制格式。文字塊最早準備在 JDK 12 新增的,但最終撤消了,然後在 JDK 13 中作為預覽特性進行了新增,然後又在 JDK 14 中再次預覽,在 JDK 15 中,文字塊終於轉正,暫不再做進一步的更改。
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
Shenandoah 垃圾回收演算法 (正式版)
Shenandoah 垃圾回收從實驗特性變為產品特性。這是一個從 JDK 12 引入的回收演算法,該演算法通過與正在執行的 Java 執行緒同時進行疏散工作來減少 GC 暫停時間。Shenandoah 的暫停時間與堆大小無關,無論堆疊是 200 MB 還是 200 GB,都具有相同的一致暫停時間。JDK 15 Shenandoah垃圾收集器從預覽特性變更為正式特性而已。
移除了 Solaris 和 SPARC 埠
移除了 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 埠的原始碼及構建支援。這些埠在 JDK 14 中就已經被標記為 deprecated 了。
外部儲存器訪問 API(二次孵化)
這個最早在 JDK 14 中成為孵化特性,JDK 15 繼續二次孵化並對其 API 有了一些更新。目的是引入一個 API,以允許 Java 程式安全有效地訪問 Java 堆之外的外部記憶體。這同樣是 Java 14 的一個預覽特性。
Records Class(二次預覽)
Records Class 也是第二次出現的預覽功能,它在 JDK 14 中也出現過一次了,使用 Record 可以更方便的建立一個常量類,使用的前後程式碼對比如下。
// before
class Point {
private final int x;
private final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
int x() { return x; }
int y() { return y; }
public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point other = (Point) o;
return other.x == x && other.y = y;
}
public int hashCode() {
return Objects.hash(x, y);
}
public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
// now
record Point(int x, int y) { }
廢除 RMI 啟用
廢除 RMI 啟用,以便在將來進行刪除。需要說明的是,RMI 啟用是 RMI 中一個過時的元件,自 Java 8 以來一直是可選的。
Java16
2021-03-16
模式匹配(正式版)
第一次預覽是 JDK 14 中提出來的
// before
if (obj instanceof String) {
String s = (String) obj;
// 使用s
}
// now
if (obj instanceof String s) {
// 使用s
}
Record型別(正式版)
Java14引入了record型別支援更加緊湊的方式去宣告一個類,而這些類能夠作為不可變資料型別的封裝持有者。
public class TestPros {
public static void main(String[] args) {
}
public record person(String name, int age) {
public String getName() {
return this.name;
}
public int getAge() {
return age;
}
}
}
打包工具Packaging Tool
提供了一個新的打包工具jpackage,用來打包獨立的Java應用程式。這個工具可以生成windows上的exe和msi,MacOS上的pkg和dmg,以及linux上的deb和rpm。它很好的給使用者提供了一鍵式安裝Java程式的好方法。
// jar
jpackage --name myapp --input lib --main-jar main.jar
// main class
jpackage --name myapp --input lib --main-jar main.jar --main-class myapp.Main
// module
jpackage --name myapp --module-path lib -m myapp
// main class in module
jpackage --name myapp --module-path lib -m myapp/myapp.Main
Elastic Metaspace
彈性的元空間,可以幫助 HotSpot 虛擬機器,將元空間中未使用的 class 元資料記憶體更及時地返回給作業系統,以減少元空間的記憶體佔用空間。另外,還簡化了元空間的程式碼,以降低維護成本。
ZGC併發執行緒處理
ZGC 是一種較新的垃圾回收器,指在解決 HotSpot 虛擬機器中的 GC 停頓及可伸縮問題。
ZGC是The Z Garbage Collector,是JDK 11中推出的一款低延遲垃圾回收器,它嘗試解決GC之痛,也就是停頓。同時,它也將面向以TB為單位的超大規模的記憶體。在Java 16中,ZGC的執行緒棧處理的眾多操作,從檢查點移動到了併發階段,這樣意味著停頓更小了。
Unix Domain套接字
Unix Domain套接字本身提供給了一套兼容於網路程式設計,但是更加可靠、高效、安全的程序間通訊方式,它不需要經過網路協議棧,不需要打包拆包、計算校驗和、維護序號和應答等,只是將應用層資料從一個程序拷貝到另一個程序。
JDK 內部預設強封裝
JDK 16 開始對 JDK 內部大部分元素預設進行強封裝,sun.misc.Unsafe 之類的關鍵內部 API 除外,從而限制對它們的訪問。此外,使用者仍然可以選擇自 JDK 9 以來的預設的寬鬆的強封裝,這樣可以幫助使用者毫不費力地升級到未來的 Java 版本。
基於值的類的警告
將基礎型別包裝類指定為基於值的類,廢除其建構函式以進行刪除,從而提示新的棄用警告。並且提供了在任何基於值的類的例項上不正常進行同步的警告。
向量API (孵化版)
Vector API 這是一個新的初始迭代孵化器模組,模組包:jdk.incubator.vector,用於表示在執行時可靠地編譯到支援的 CPU 架構上的最佳向量硬體指令的向量計算。
外部連結API (孵化版)
Foreign Linker API 提供了一個靜態的,純Java的訪問本地native 程式碼的方法,它將極大簡化我們呼叫原生代碼的過程,是JNI的進化版。
外部記憶體訪問 API(孵化版)
引入了一個新的 API,可以幫助 Java 應用程式更安全、有效地訪問 Java 堆之外的外部記憶體。
封閉類 (第二次預覽)
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
啟用 C++14 語言特性
它允許在 JDK C++ 原始碼中使用 C++14 語言特性,並提供在 HotSpot 程式碼中可以使用哪些特性的具體指導。在 JDK 15 中,JDK 中 C++ 程式碼使用的語言特性僅限於 C++98/03 語言標準。它要求更新各種平臺編譯器的最低可接受版本。
從 Mercurial 遷移到 Git,遷移到 GitHub
將 OpenJDK 社群的原始碼儲存庫從 Mercurial(hg)遷移到 Git,並將它們託管在 GitHub 上以供 JDK 11 及更高版本使用,其中包括將 jcheck、webrev 和 defpath 工具等工具更新到 Git。Git 減小了元資料的大小(約 1/4),可節省本地磁碟空間並減少克隆時間。與 Mercurial 相比,現代工具鏈可以更好地與 Git 整合。
Windows/AArch64 移植
將 JDK 移植到 Windows/ AArch64 平臺系列。
Java17
2021-09-14
長期支援版本,支援到2029年9月
密封類 Sealed Classes (正式版)
public abstract sealed class Student
permits ZhangSan, LiSi, ZhaoLiu {
...
}
為 switch 支援模式匹配 (預覽版)
// before
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
// now
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
恢復始終執行嚴格模式的浮點定義
Java 最初只有嚴格的浮點語義,但從 JDK 1.2 開始,為了適應當時硬體架構的限制,預設情況下允許這些嚴格語義中的細微變化,而現在這些都沒有必要了,已被 JEP 306 刪除。
增強型偽隨機數生成器
增強型偽隨機數生成器,java.util.random 包更新了,提高了不同 PRNGs(偽隨機數生成器)的互操作性,並使基於需求而不是硬編碼特定實現的演算法變得容易。
這次更改包括偽隨機數生成器(PRNG)的新的介面型別和實現,包括可跳 PRNGs 和一個可拆分的 PRNG 演算法(LXM),以及全新的 RandomGeneratorFactory 類。
新的 macOS 渲染管道
這個新管道通過使用新的 Apple Metal API 為 macOS 實現 Java 2D 渲染管道,減少了 JDK 對已棄用的 Apple OpenGL API 的依賴。
macOS AArch64 埠
macOS AArch64 埠,即提供可適用於 macOS 的 JDK 版本,該版本可在基於 Arm 64 的較新的 macOS 系統上本地化執行。
棄用 Applet API
Applet 是一種執行在 Web 瀏覽器內的 Java 程式,但 Applet 早就沒什麼實際用途了。
JDK 內部強封裝
JDK 16 開始對 JDK 內部大部分元素預設進行強封裝,sun.misc.Unsafe
之類的關鍵內部 API 除外,從而限制對它們的訪問。此外,使用者仍然可以選擇自 JDK 9 以來的預設的寬鬆的強封裝,這樣可以幫助使用者毫不費力地升級到未來的 Java 版本。
移除 RMI 啟用
RMI 啟用機制已於 2020 年 9 月在 JDK 15 中移除了,遠端方法呼叫 (RMI) 啟用機制現也已被移除,需要說明的是,RMI 啟用是 RMI 中一個過時的元件,自 Java 8 以來一直是可選的。
移除實驗性的 AOT 和 JIT 編譯器
AOT 和 JIT 這兩個實驗性的編譯器,自從在 JDK 9 中引入以來幾乎沒有怎麼使用,市面上也出現了更為廣泛使用的替代方案,並且維護它們所需的工作量很大,所以在 JDK 16 中就已經刪除了,本次從 OpenJDK 專案中刪除了原始碼。
棄用安全管理器
安全管理器從 Java 1.0 開始,這些年來它一直都不是保護 Java 應用程式程式碼的主要手段,也很少用於保護 Java 伺服器端程式碼,所以這個版本標識為棄用狀態了,未來的版本會進行移除。
外部函式和記憶體 API(孵化中)
改進了 JDK 14 和 JDK 15 引入的 API,通過有效呼叫外部函式(即 JVM 之外的程式碼),以及安全地訪問外部記憶體(JVM 之外的記憶體),這些 API 可以呼叫本地庫和處理本地資料,與 Java 執行環境之外的程式碼和資料進行互動。
向量 API(二次孵化中)
Vector API 這是一個新的初始迭代孵化器模組,模組包:jdk.incubator.vector,用於表示在執行時可靠地編譯到支援的 CPU 架構上的最佳向量硬體指令的向量計算,向量運算可以提供優於等效標量計算的效能,並且在機器學習、人工智慧和密碼學等領域非常普遍。
本次增強的 API 允許以一種在執行時,可靠地編譯為支援的 CPU 架構上的最佳向量指令的方式表達向量計算。
上下文特定反序列化過濾器
允許應用配置 context-specific 和 dynamically-selected 過濾器,通過一個 JVM 範圍的過濾器工廠,用來為每個單獨的反序列化操作選擇一個過濾器。
JDK 17 免費
Oracle 宣佈,從 JDK 17 開始,後面的 JDK 都全部免費提供
Oracle JDK17 與 OpenJDK 17 區別:
- Oracle JDK 提供了各種安裝程式,還包含更新規則,而 OpenJDK 只提供了一個純壓縮包;
- Usage Logging 僅在 Oracle JDK 中可用;
- Oracle JDK 要求第三方加密提供程式使用 Java 加密擴充套件(JCE)進行簽名,而 OpenJDK 繼續允許使用未簽名的第三方加密提供程式;
- java -version 的輸出也是不同的,Oracle JDK 返回 java 幷包含 Oracle 特定的識別符號,OpenJDK 返回 OpenJDK 並且不包含特定於 Oracle 的識別符號;
- 許可證不同,Oracle JDK 17+ 是根據 Oracle 免費條款和條件許可釋出的,而 OpenJDK 在 GPLv2wCP 下發布的;
- Oracle JDK 原始碼含有 "ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.",其使用受許可條款約束的,而 OpenJDK 原始碼可參考 GPL 許可條款;
Oracle JDK 17 下載地址:
https://www.oracle.com/java/technologies/javase-downloads.html
OpenJDK 17 下載地址: