一、版本roadmap圖
官方地址:
https://www.oracle.com/java/technologies/java-se-support-roadmap.html
從上圖可以很清晰得可以看出,JDK7,JDK8,JDK11,JDK17,JDK21是長期維護的版本。從目前來看,JDK8到2023年已經(jīng)有將近10年的歷史了,大多數(shù)依據(jù)JDK8的相關(guān)技術(shù)內(nèi)容已經(jīng)很成熟了,但是大家也看到,JDK在不斷地迭代,JDK有很多的新特性,而且能夠?qū)﹂_發(fā)及系統(tǒng)性能有很大幫助。所以現(xiàn)在很多公司在建新系統(tǒng)的時候,在考慮新的JDK。再加上重要的一點是新的spring boot3及對應(yīng)的spring cloud 2022.X及以上版本,最低支持的JDK也需要JDK17了。所以要想跟上技術(shù)迭代,還需我們自己對于JDK進行了解,然后根據(jù)自己的實際選擇相應(yīng)的版本。
二、版本與特性
特性列表(包含正式特性,孵化的,未孵化的等)
JEP 0: JEP Index
值得注意的是,每個jdk有對應(yīng)的新特性,但是有些特性在經(jīng)歷幾個jdk的迭代后,被移除了,或者被更好的特性所取代了。
Java8特性
1.Lambda 表達式
其他語言都已陸續(xù)推出Lambda 表達式,java也不落后。
Lambda 表達式簡單來講是一個匿名函數(shù),Java 8 允許將函數(shù)作為參數(shù)傳遞到方法之中。
它是 Java 8 發(fā)布的最為重要的新特性之一,跟上了目前語言發(fā)展的趨勢,是繼泛型(Generics)和注解(Annotation)以來最大的突破。
采用 Lambda 表達式可以大幅簡化代碼的編寫,開發(fā)人員在熟練之后,可以很簡單的書寫相關(guān)的功能,并且提升了相應(yīng)的效率,這就是函數(shù)式編程。
2.Stream流
Stream流計算是一個跟當(dāng)前很貼合的,隨著計算能力提升及數(shù)據(jù)量的增加,這個是有必要的。有鑒于此,Java 新增了 java.util.stream 包,它和以前的流十分類似。以前我們最常接觸到的是資源流,例如 java.io.FileInputStream,它通過流的方式把文件從一個地方輸入到另一個地方,與文件內(nèi)容無關(guān),只是一種內(nèi)容搬運工作,不涉及任何 CRUD 操作。
java8的兩種流類型:
- stream 串行流
- parallelStream 并行流
Stream 的源數(shù)據(jù)來于?Collection、Arrays 等類型,因為它的方法參數(shù)都是函數(shù)式接口類型,所以通常和 Lambda 表達式一起使用。
Stream 不存儲數(shù)據(jù),也不改變源數(shù)據(jù),但它提供了對集合數(shù)據(jù)進行檢索和邏輯處理的功能,包括篩選、排序、統(tǒng)計、計數(shù)等??梢孕蜗蟮貙⑵浔茸?SQL 語句。
3.Optional
主要用來處理傳入的數(shù)據(jù)的空指針NullPointerException問題。
假設(shè)有一個 Person?類,里面有個屬性 Hobby,需求要獲取Hobby的 scope。
class?Person?{
???private?Hobby hobby;
}
class?Hobby {
???private?String scope;
}
我們以前這樣寫:
Person??person =?buildPerson();
if (person !=?null) {
???Hobby hobby =?person.getHobby();
???if (hobby !=?null) {
??????String scope =?hobby.getScope();
??????System.out.println(scope);
???}
}
用了Optional :
Optional.ofNullable(person)
.map(p?-> p.getHobby())
.map(h?-> h.getScope())
.ifPresent(scope?->System.out.println(scope));
4.Interface
Interface 的初始設(shè)計目的是面向抽象,提高可擴展性。但這也帶來了一個不足之處,即當(dāng) Interface 進行修改時,實現(xiàn)它的類也必須相應(yīng)地進行修改。
為了解決 Interface 修改與現(xiàn)有實現(xiàn)不兼容的問題,現(xiàn)在可以使用 default 或 static 關(guān)鍵詞修飾 interface 的方法,這樣就可以給方法提供一個默認(rèn)實現(xiàn),而實現(xiàn)類無需重寫此方法。
一個 Interface 中可以有多個方法被這兩種關(guān)鍵詞所修飾。二者的區(qū)別在于,default 方法是普通實例方法,可以使用 this 關(guān)鍵詞調(diào)用,可以被子類繼承和重寫;而 static 方法與一般類的靜態(tài)方法類似,無法被子類繼承,只能通過 Interface 調(diào)用。
如果有一個類既實現(xiàn)了 2個接口,都有相同名稱的方法,并且兩個接口沒有繼承關(guān)系的話,這時就必須重寫同名方法()。不然的話,編譯的時候就會報錯。
public interface InterfacePerson {
static void staticInterfacePerson() {
System.out.println("InterfacePerson 的 靜態(tài) staticInterfacePerson");
}
static void staticInterfacePerson2() {
System.out.println("InterfacePerson 的 靜態(tài) staticInterfacePerson2");
}
default void defaultInterfacePerson() {
System.out.println("InterfacePerson 的 默認(rèn) defaultInterfacePerson");
}
default void defaultInterfacePerson2() {
System.out.println("InterfacePerson 的 默認(rèn) defaultInterfacePerson2");
}
}
public interface InterfacePerson2 {
static void staticInterfacePerson() {
System.out.println("InterfacePerson2 的 靜態(tài) staticInterfacePerson");
}
default void defaultInterfacePerson() {
System.out.println("InterfacePerson2 的 默認(rèn) defaultInterfacePerson");
}
}
public class Person implements InterfacePerson, InterfacePerson2 {
}
?
?
當(dāng)然我們也可以看到j(luò)ava8和java7接口的不同:
????????java7當(dāng)中接口里面,只能含有常量和抽象方法
????????java8增加了默認(rèn)與靜態(tài)方法
以下是切換到j(luò)ava7的結(jié)果:
???
?java9增加了私有方法
?以下是JDK17的時候接口的寫法,接口是越來越強大的,以下編譯報錯的都是不支持的。
1.變量
?2方法
?
5.functional interface 函數(shù)式接口
定義:有且只有一個抽象方法,但可以有多個非抽象方法的接口。
在 java 8 中專門有一個包放函數(shù)式接口java.util.function,該包下的所有接口都有 @FunctionalInterface?注解,提供函數(shù)式編程。
在其他包中也有函數(shù)式接口,其中一些沒有@FunctionalInterface?注解,但是只要符合函數(shù)式接口的定義就是函數(shù)式接口,與是否有@FunctionalInterface注解無關(guān),注解只是在編譯時起到強制規(guī)范定義的作用。其在 Lambda 表達式中有廣泛的應(yīng)用。
@FunctionalInterface
public interface TestFunction<T, U,E,F,G,GH,HV, R> {
R apply(T t, U u, E e, F f, G g, GH gh, HV hv);
}
6.Date-Time API
這是對java.util.Date強有力的補充,解決了 Date 類的大部分痛點:
- 非線程安全
- 時區(qū)處理麻煩
- 各種格式化、和時間計算繁瑣
- 設(shè)計有缺陷,Date 類同時包含日期和時間;還有一個 java.sql.Date,容易混淆。
java9新特性
1.模塊化系統(tǒng)
java9的時候最大的一個新特性是模塊化系統(tǒng),模塊系統(tǒng)的核心原理是將應(yīng)用程序劃分為一組模塊,并通過 module-info.java 文件來定義模塊的信息和依賴關(guān)系?
Java 應(yīng)用可以通過新增的Jlink工具?(Jlink 是隨 Java 9 一起發(fā)布的新命令行工具。JDK 9 引入的新特性允許開發(fā)人員為基于模塊化的 Java 應(yīng)用程序創(chuàng)建自定義、輕量級的 JRE(Java Runtime Environment)。開發(fā)人員可以根據(jù)所依賴的 JDK 模塊創(chuàng)建自定義的運行時鏡像,這將大大減少 Java 運行時環(huán)境的大小。
我們可以通過 exports?關(guān)鍵詞控制模塊及使用范圍。
module?limit.module?{
????//exports 公開指定包的所有公共成員
????exports?com.my.package.name;}
module?limit.module?{
?????//exports…to 限制訪問的成員范圍
????export com.limit.package.name to?com.target.limit.package;
}
2.G1 成為默認(rèn)垃圾回收器
在 Java 8 中,默認(rèn)使用的垃圾回收器為 Parallel Scavenge(新生代)+Parallel Old(老年代)。但到了 Java 9,CMS 垃圾回收器被棄用,取而代之的是 G1(Garbage-First Garbage Collector),成為新的默認(rèn)垃圾回收器。
實際上,G1 垃圾回收器在 Java 7 中就已經(jīng)被引入,而經(jīng)過兩個版本的表現(xiàn)表現(xiàn)優(yōu)異后,它于 Java 9 成為了默認(rèn)的垃圾回收器。
3.接口私有方法
Java 9 允許在接口中使用私有方法。
public?interface?PrivateInterface?{
????private?void?privateM(){
????}
}
4.快速創(chuàng)建不可變集合
增加了List.of()、Set.of()、Map.of()?和 Map.ofEntries()等工廠方法來創(chuàng)建不可變集合。使用 of()?創(chuàng)建的集合為不可變集合,不能進行添加、刪除、替換、 排序等操作,不然會報 java.lang.UnsupportedOperationException?異常。
5.String 存儲結(jié)構(gòu)優(yōu)化
Java 8 及之前的版本,String?一直是用?char[]?存儲。在 Java 9 之后,String?的實現(xiàn)改用?byte[]?數(shù)組存儲字符串,節(jié)省了空間。
6.try-with-resources 增強
在 Java 9 之前,我們只能在 try-with-resources?塊中聲明變量:
try (FileInputStream inputStream = new FileInputStream("a.txt");) {
} catch (IOException e) {
throw new RuntimeException(e);
}
在 Java 9 之后,在 try-with-resources?語句中可以使用 effectively-final 變量。
final FileInputStream inputStream = new FileInputStream("a.txt");
try (inputStream) {
} catch (IOException e) {
throw new RuntimeException(e);
}
什么是 effectively-final 變量??如果對象或基礎(chǔ)類型的變量在初始化后值不發(fā)生改變,則可以把它們看做?effectively?final
7.Stream & Optional 增強
Stream?中增加了新的方法 ofNullable()、dropWhile()、takeWhile()?以及 iterate()?方法的重載方法。
8.進程 API
Java 9 增加了 java.lang.ProcessHandle?接口來實現(xiàn)對原生進程進行管理,尤其適合于管理長時間運行的進程。
9.響應(yīng)式流 ( Reactive Streams )
在 Java 9 中的 java.util.concurrent.Flow?類中新增了反應(yīng)式流規(guī)范的核心接口 。
Flow?中包含了 Flow.Publisher、Flow.Subscriber、Flow.Subscription?和 Flow.Processor?等 4 個核心接口。Java 9 還提供了SubmissionPublisher?作為Flow.Publisher?的一個實現(xiàn)。
10.變量句柄
變量句柄是一個變量或一組變量的引用,包括靜態(tài)域,非靜態(tài)域,數(shù)組元素和堆外數(shù)據(jù)結(jié)構(gòu)中的組成部分等。
變量句柄的含義類似于已有的方法句柄 MethodHandle?,由 Java 類 java.lang.invoke.VarHandle?來表示,可以使用類 java.lang.invoke.MethodHandles.Lookup?中的靜態(tài)工廠方法來創(chuàng)建 VarHandle?對象。
VarHandle?的出現(xiàn)替代了 java.util.concurrent.atomic?和 sun.misc.Unsafe?的部分操作。并且提供了一系列標(biāo)準(zhǔn)的內(nèi)存屏障操作,用于更加細(xì)粒度的控制內(nèi)存排序。在安全性、可用性、性能上都要優(yōu)于現(xiàn)有的 API。
11.平臺日志 API 改進?
Java 9 允許為 JDK 和應(yīng)用配置同樣的日志實現(xiàn)。新增了 System.LoggerFinder?用來管理 JDK 使 用的日志記錄器實現(xiàn)。JVM 在運行時只有一個系統(tǒng)范圍的 LoggerFinder?實例。我們可以通過添加自己的 System.LoggerFinder?實現(xiàn)來讓 JDK 和應(yīng)用使用 SLF4J 等其他日志記錄框架。
12.CompletableFuture類增強?
新增了幾個新的方法(completeAsync?,orTimeout?等)。
13.I/O 流的新特性?
增加了新的方法來讀取和復(fù)制 InputStream?中包含的數(shù)據(jù)。
14.改進方法句柄(Method Handle)?
方法句柄從 Java7 開始引入,Java9 在類java.lang.invoke.MethodHandles?中新增了更多的靜態(tài)方法來創(chuàng)建不同類型的方法句柄。
java10新特性
1.局部變量類型推斷(var)
Java 10 提供了 var?關(guān)鍵字聲明局部變量。
var i = 0;
var url = new URL("https://mp.weixin.qq.com/");
var list = new ArrayList<>();
var map = new HashMap<String, String>();
for (var n : list){
System.out.print(n+ " ");
}
var不能聲明為 null,不能聲明為 Lambda表達式。
2.垃圾回收器接口
在早期的 JDK 結(jié)構(gòu)中,組成垃圾收集器 (GC) 實現(xiàn)的組件分散在代碼庫的各個部分。 Java 10 通過引入一套純凈的垃圾收集器接口來將不同垃圾收集器的源代碼分隔開。
3.G1 并行 Full GC
從 Java9 開始 G1 就了默認(rèn)的垃圾回收器,G1 是以一種低延時的垃圾回收器來設(shè)計的,旨在避免進行 Full GC,但是 Java9 的 G1 的 FullGC 依然是使用單線程去完成標(biāo)記清除算法,這可能會導(dǎo)致垃圾回收期在無法回收內(nèi)存的時候觸發(fā) Full GC。
為了最大限度地減少 Full GC 造成的應(yīng)用停頓的影響,從 Java10 開始,G1 的 FullGC 改為并行的標(biāo)記清除算法,同時會使用與年輕代回收和混合回收相同的并行工作線程數(shù)量,從而減少了 Full GC 的發(fā)生,以帶來更好的性能提升、更大的吞吐量。
4集合增強
List,Set,Map?提供了靜態(tài)方法copyOf()返回入?yún)⒓系囊粋€不可變拷貝。
static?<E>?List<E>?copyOf(Collection<? extends E>?coll)?{
????return?ImmutableCollections.listCopy(coll);
}
使用 copyOf()?創(chuàng)建的集合為不可變集合,不能進行添加、刪除、替換、 排序等操作,不然會報 java.lang.UnsupportedOperationException?異常。?
并且,java.util.stream.Collectors?中新增了靜態(tài)方法,用于將流中的元素收集為不可變的集合。
var?list =?new?ArrayList<>();
list.stream().collect(Collectors.toUnmodifiableList());
list.stream().collect(Collectors.toUnmodifiableSet());
5.Optional 增強
Optional?新增了orElseThrow()方法來在沒有值時拋出指定的異常。
Optional.ofNullable(cache.getIfPresent(key))
????????.orElseThrow(()?->?new?PersonalException(?"personal Exception for key: "?+?key));
6.應(yīng)用程序類數(shù)據(jù)共享(擴展 CDS 功能)
在 Java 5 中就已經(jīng)引入了類數(shù)據(jù)共享機制 (Class Data Sharing,簡稱 CDS),允許將一組類預(yù)處理為共享歸檔文件,以便在運行時能夠進行內(nèi)存映射以減少 Java 程序的啟動時間,當(dāng)多個 Java 虛擬機(JVM)共享相同的歸檔文件時,還可以減少動態(tài)內(nèi)存的占用量,同時減少多個虛擬機在同一個物理或虛擬的機器上運行時的資源占用。CDS 在當(dāng)時還是 Oracle JDK 的商業(yè)特性。
Java 10 在現(xiàn)有的 CDS 功能基礎(chǔ)上再次拓展,以允許應(yīng)用類放置在共享存檔中。CDS 特性在原來的 bootstrap 類基礎(chǔ)之上,擴展加入了應(yīng)用類的 CDS 為 (Application Class-Data Sharing,AppCDS) 支持,大大加大了 CDS 的適用范圍。其原理為:在啟動時記錄加載類的過程,寫入到文本文件中,再次啟動時直接讀取此啟動文本并加載。設(shè)想如果應(yīng)用環(huán)境沒有大的變化,啟動速度就會得到提升。
7.線程-局部管控
Java 10 中線程管控引入 JVM 安全點的概念,將允許在不運行全局 JVM 安全點的情況下實現(xiàn)線程回調(diào),由線程本身或者 JVM 線程來執(zhí)行,同時保持線程處于阻塞狀態(tài),這種方式使得停止單個線程變成可能,而不是只能啟用或停止所有線程
8.備用存儲裝置上的堆分配
Java 10 中將使得 JVM 能夠使用適用于不同類型的存儲機制的堆,在可選內(nèi)存設(shè)備上進行堆內(nèi)存分配
java11新特性
1.HTTP Client 標(biāo)準(zhǔn)化
Java 11 標(biāo)準(zhǔn)化了 Java 9 中引入的 Http Client API,并在 Java 10 中進行了更新。在前兩個版本中對 Http Client 進行孵化的同時,該 API 幾乎被完全重寫,并且現(xiàn)在已經(jīng)完全支持異步非阻塞。
此外,Java 11 中,Http Client 的包名已由 jdk.incubator.http 更改為 java.net.http。該 API 通過 CompleteableFuture 提供了非阻塞請求和響應(yīng)語義。使用起來也非常簡單,例如:
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);
2.啟動單文件源代碼程序
這意味著我們可以運行單一文件的 Java 源代碼。此功能允許使用 Java 解釋器直接執(zhí)行 Java 源代碼。源代碼在內(nèi)存中編譯,然后由解釋器執(zhí)行,不需要在磁盤上生成 .class?文件了。唯一的約束在于所有相關(guān)的類必須定義在同一個 Java 文件中。
對于 Java 初學(xué)者并希望嘗試簡單程序的人特別有用,并且能和 jshell 一起使用。一定能程度上增強了使用 Java 來寫腳本程序的能力。
3.新的垃圾回收器 Epsilon?
一個完全消極的 GC 實現(xiàn),分配有限的內(nèi)存資源,最大限度的降低內(nèi)存占用和內(nèi)存吞吐延遲時間
4.低開銷的 Heap Profiling?
Java 11 中提供一種低開銷的 Java 堆分配采樣方法,能夠得到堆分配的 Java 對象信息,并且能夠通過 JVMTI 訪問堆信息
5.飛行記錄器(Java Flight Recorder)?
飛行記錄器之前是商業(yè)版 JDK 的一項分析工具,但在 Java 11 中,其代碼被包含到公開代碼庫中,這樣所有人都能使用該功能了。
6.String 增強
Java 11 增加了一系列的字符串處理方法:
//判斷字符串是否為空
System.out.println(" ".isBlank());
// 去除字符串首尾空格
System.out.println("結(jié)果:"+" 去除字符串首尾空格 ".strip()+"結(jié)束");
// 去除字符串首部空格
System.out.println("結(jié)果:"+"去除字符串首部空格 ".stripLeading()+"結(jié)束");
// 去除字符串尾部空格
System.out.println("結(jié)果:"+" 去除字符串尾部空格 ".stripTrailing()+"結(jié)束");
// 重復(fù)字符串多少次
System.out.println(" 重復(fù)字符串多少次 ".repeat(2));
// 返回由行終止符分隔次數(shù)。
System.out.println("A\nB\nC".lines().count());
// 返回由行終止符分隔的字符串集合。
System.out.println("A\nB\nC".lines().collect(Collectors.toList()));
7.Optional 增強
新增了empty()方法來判斷指定的 Optional?對象是否為空。
var?obj=?Optional.empty();
//判斷指定的 Optional 對象是否為空
System.out.println(obj.isEmpty());
8.Lambda 參數(shù)的局部變量語法
從 Java 10 開始,便引入了局部變量類型推斷這一關(guān)鍵特性。類型推斷允許使用關(guān)鍵字 var 作為局部變量的類型而不是實際類型,編譯器根據(jù)分配給變量的值推斷出類型。
Java 10 中對 var 關(guān)鍵字存在幾個限制
- 只能用于局部變量上
- 聲明時必須初始化
- 不能用作方法參數(shù)
- 不能在 Lambda 表達式中使用
Java11 開始允許開發(fā)者在 Lambda 表達式中使用 var 進行參數(shù)聲明。
// 下面兩者是等價的
Consumer<String>?consumer =?(var?c)?->?System.out.println(c);
Consumer<String>?consumer =?(String?c)?->?System.out.println(c);
java12新特性
1.數(shù)字格式化工具類
NumberFormat?新增了對復(fù)雜的數(shù)字進行格式化的支持
NumberFormat fmtShort = NumberFormat.getCompactNumberInstance(Locale.CHINESE, NumberFormat.Style.SHORT);
String resultShort = fmtShort.format(10000000);
System.out.println(resultShort);
NumberFormat fmt2Short = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String result2Short = fmt2Short.format(10000000);
System.out.println(result2Short);
NumberFormat fmtLong = NumberFormat.getCompactNumberInstance(Locale.CHINESE, NumberFormat.Style.LONG);
String resultLong = fmtLong.format(10000000);
System.out.println(resultLong);
NumberFormat fmt2Long = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.LONG);
String result2Long = fmt2Long.format(10000000);
System.out.println(result2Long);
輸出:
2.Shenandoah GC
Redhat 主導(dǎo)開發(fā)的 Pauseless GC 實現(xiàn),主要目標(biāo)是 99.9% 的暫停小于 10ms,暫停與堆大小無關(guān)等
和 Java11 開源的 ZGC 相比(需要升級到 JDK11 才能使用),Shenandoah GC 有穩(wěn)定的 JDK8u 版本,在 Java8 占據(jù)主要市場份額的今天有更大的可落地性。
3.String 增強
Java 11 增加了兩個的字符串處理方法
1.indent() 方法可以實現(xiàn)字符串縮進。
public String indent(int n) {
if (isEmpty()) {
return "";
}
Stream<String> stream = lines();
if (n > 0) {
final String spaces = " ".repeat(n);
stream = stream.map(s -> spaces + s);
} else if (n == Integer.MIN_VALUE) {
stream = stream.map(s -> s.stripLeading());
} else if (n < 0) {
stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace())));
}
return stream.collect(Collectors.joining("\n", "", "\n"));
}
2.transform() 方法可以用來轉(zhuǎn)變指定字符串。
public <R> R transform(Function<? super String, ? extends R> f) {
return f.apply(this);
}
如以下所示。
//indent() 方法可以實現(xiàn)字符串縮進。
String text = "縮進";
// 縮進 4 格
text = text.indent(4);
System.out.println(text);
//transform() 增加的直接使用的方法函數(shù)式編程方法。
String result = "源數(shù)據(jù)".transform(input -> input + " 增加");
System.out.println(result);
?
4.Files 增強(文件比較)
Java 12 添加了以下方法來比較兩個文件:
public?static?long?mismatch(Path?path,?Path?path2)?throws?IOException
mismatch()?方法用于比較兩個文件,并返回第一個不匹配字符的位置,如果文件相同則返回 -1L。
5.G1 收集器優(yōu)化
Java12 為默認(rèn)的垃圾收集器 G1 帶來了兩項更新:
- 可中止的混合收集集合?:JEP344 的實現(xiàn),為了達到用戶提供的停頓時間目標(biāo),JEP 344 通過把要被回收的區(qū)域集(混合收集集合)拆分為強制和可選部分,使 G1 垃圾回收器能中止垃圾回收過程。 G1 可以中止可選部分的回收以達到停頓時間目標(biāo)
- 及時返回未使用的已分配內(nèi)存?:JEP346 的實現(xiàn),增強 G1 GC,以便在空閑時自動將 Java 堆內(nèi)存返回給操作系統(tǒng)
Java13新特性
1.增強 ZGC(釋放未使用內(nèi)存)
在 Java 11 中是實驗性的引入的 ZGC 在實際的使用中存在未能主動將未使用的內(nèi)存釋放給操作系統(tǒng)的問題。
ZGC 堆由一組稱為 ZPages 的堆區(qū)域組成。在 GC 周期中清空 ZPages 區(qū)域時,它們將被釋放并返回到頁面緩存 ZPageCache?中,此緩存中的 ZPages 按最近最少使用(LRU)的順序,并按照大小進行組織。
在 Java 13 中,ZGC 將向操作系統(tǒng)返回被標(biāo)識為長時間未使用的頁面,這樣它們將可以被其他進程重用。
2.SocketAPI 重構(gòu)
Java Socket API 終于迎來了重大更新!
Java 13 將 Socket API 的底層進行了重寫, NioSocketImpl?是對 PlainSocketImpl?的直接替代,它使用 java.util.concurrent?包下的鎖而不是同步方法。如果要使用舊實現(xiàn),請使用 -Djdk.net.usePlainSocketImpl=true。
并且,在 Java 13 中是默認(rèn)使用新的 Socket 實現(xiàn)。
public?final?class?NioSocketImpl?extends?SocketImpl?implements?PlatformSocketImpl?{}
3.FileSystems
FileSystems?類中添加了以下三種新方法,以便更容易地使用將文件內(nèi)容視為文件系統(tǒng)的文件系統(tǒng)提供程序:
- newFileSystem(Path)
- newFileSystem(Path, Map<String, ?>)
- newFileSystem(Path, Map<String, ?>, ClassLoader)
4.動態(tài) CDS 存檔
Java 13 中對 Java 10 中引入的應(yīng)用程序類數(shù)據(jù)共享(AppCDS)進行了進一步的簡化、改進和擴展,即:允許在 Java 應(yīng)用程序執(zhí)行結(jié)束時動態(tài)進行類歸檔,具體能夠被歸檔的類包括所有已被加載,但不屬于默認(rèn)基層 CDS 的應(yīng)用程序類和引用類庫中的類。
這提高了應(yīng)用程序類數(shù)據(jù)共享(AppCDSopen in new window)的可用性。無需用戶進行試運行來為每個應(yīng)用程序創(chuàng)建類列表。
$ java?-XX:ArchiveClassesAtExit=my_app_cds.jsa -cp?my_app.jar
$ java?-XX:SharedArchiveFile=my_app_cds.jsa -cp?my_app.jar
Java14新特性
1.空指針異常精準(zhǔn)提示
通過 JVM 參數(shù)中添加-XX:+ShowCodeDetailsInExceptionMessages,可以在空指針異常中獲取更為詳細(xì)的調(diào)用信息,更快的定位和解決問題。
a.b.c.i =?99;?// 假設(shè)這段代碼會發(fā)生空指針
Java 14 之前:
Exception?in thread "main"?java.lang.NullPointerException
????at NullPointerExample.main(NullPointerExample.java:5)
Java 14 之后:
?// 增加參數(shù)后提示的異常中很明確的告知了哪里為空導(dǎo)致Exception?in thread "main"?java.lang.NullPointerException:
????????Cannot?read field 'c'?because 'a.b'?is null.
????at Prog.main(Prog.java:5)
2.switch 的增強(轉(zhuǎn)正)
Java12 引入的 switch(預(yù)覽特性)在 Java14 變?yōu)檎桨姹?,不需要增加參?shù)來啟用,直接在 JDK14 中就能使用。
Java12 為 switch 表達式引入了類似 lambda 語法條件匹配成功后的執(zhí)行塊,不需要多寫 break ,Java13 提供了 yield?來在 block 中返回值。
3.ZGC支持
從 Java11 引入的 ZGC 作為繼 G1 過后的下一代 GC 算法,從支持 Linux 平臺到 Java14 開始支持 MacOS 和 Window
4.移除 CMS
移除了 CMS(Concurrent Mark Sweep) 垃圾收集器
5.新增了 jpackage 工具
jpackage 工具,標(biāo)配將應(yīng)用打成 jar 包外,還支持不同平臺的特性包,比如 linux 下的deb和rpm,window 平臺下的msi和exe
Java15新特性
1.隱藏類(Hidden Classes)
隱藏類是為框架(frameworks)所設(shè)計的,隱藏類不能直接被其他類的字節(jié)碼使用,只能在運行時生成類并通過反射間接使用它們。
2.TreeMap增強
TreeMap?新引入了下面這些方法:
- putIfAbsent()
- computeIfAbsent()
- computeIfPresent()
- compute()
- merge()
3.ZGC
Java11 的時候 ,ZGC 還在試驗階段。
當(dāng)時,ZGC 的出現(xiàn)讓眾多 Java 開發(fā)者看到了垃圾回收器的另外一種可能,因此備受關(guān)注。
經(jīng)過多個版本的迭代,不斷的完善和修復(fù)問題,ZGC 在 Java 15 已經(jīng)可以正式使用了!
不過,默認(rèn)的垃圾回收器依然是 G1。你可以通過下面的參數(shù)啟動 ZGC:
$ java?-XX:+UseZGC?className
4.文本塊
在 Java 15 ,文本塊是正式的功能特性了。
5.禁用和廢棄偏向鎖(Biased Locking)?
偏向鎖的引入增加了 JVM 的復(fù)雜性大于其帶來的性能提升。不過,你仍然可以使用 -XX:+UseBiasedLocking?啟用偏向鎖定,但它會提示 這是一個已棄用的 API。
java16新特性
1.啟用 C++ 14 語言特性
Java 16 允許在 JDK 的 C++ 源代碼中使用 C++14 語言特性,并提供在 HotSpot 代碼中可以使用哪些特性的具體指導(dǎo)。
在 Java 15 中,JDK 中 C++ 代碼使用的語言特性僅限于 C++98/03 語言標(biāo)準(zhǔn)。它要求更新各種平臺編譯器的最低可接受版本。
2.ZGC 并發(fā)線程堆棧處理
Java16 將 ZGC 線程棧處理從安全點轉(zhuǎn)移到一個并發(fā)階段,甚至在大堆上也允許在毫秒內(nèi)暫停 GC 安全點。消除 ZGC 垃圾收集器中最后一個延遲源可以極大地提高應(yīng)用程序的性能和效率。
3.彈性元空間
自從引入了 Metaspace 以來,根據(jù)反饋,Metaspace 經(jīng)常占用過多的堆外內(nèi)存,從而導(dǎo)致內(nèi)存浪費。彈性元空間這個特性可將未使用的 HotSpot 類元數(shù)據(jù)(即元空間,metaspace)內(nèi)存更快速地返回到操作系統(tǒng),從而減少元空間的占用空間。
4.打包工具
在 Java 14 中,JEP 343 引入了打包工具,命令是 jpackage。在 Java 15 中,繼續(xù)孵化,現(xiàn)在在 Java 16 中,終于成為了正式功能。
5.instanceof 模式匹配(轉(zhuǎn)正)
JDK 版本 |
更新類型 |
JEP |
更新內(nèi)容 |
Java SE 14 |
preview |
JEP 305open in new window |
首次引入 instanceof 模式匹配。 |
Java SE 15 |
Second Preview |
JEP 375open in new window |
相比較上個版本無變化,繼續(xù)收集更多反饋。 |
Java SE 16 |
Permanent Release |
JEP 394open in new window |
模式變量不在隱式為 final。 |
從 Java 16 開始,你可以對 instanceof?中的變量值進行修改。
String o = "";
// 原來
if (o instanceof String) {
String s = (String) o;
}
Object c = null;
c = "";
// 新的
if (c instanceof String b) {
b = "b";
System.out.println("c=" + c);
System.out.println("b=" + b);
}
?
6.記錄類型
記錄類型變更歷史:
JDK 版本 |
更新類型 |
JEP |
更新內(nèi)容 |
Java SE 14 |
Preview |
JEP 359open in new window |
引入 record?關(guān)鍵字,record?提供一種緊湊的語法來定義類中的不可變數(shù)據(jù)。 |
Java SE 15 |
Second Preview |
JEP 384open in new window |
支持在局部方法和接口中使用 record。 |
Java SE 16 |
Permanent Release |
JEP 395open in new window |
非靜態(tài)內(nèi)部類可以定義非常量的靜態(tài)成員。 |
從 Java SE 16 開始,非靜態(tài)內(nèi)部類可以定義非常量的靜態(tài)成員。
public?class?Outer?{
class?Inner?{
static?int?age;
}
}
在 JDK 16 之前,如果寫上面這種代碼,IDE 會提示你靜態(tài)字段 age 不能在非靜態(tài)的內(nèi)部類中定義,除非它用一個常量表達式初始化。
java17新特性
Java 17 將是繼 Java 8 以來最重要的長期支持(LTS)版本,是 Java 社區(qū)八年努力的成果。Spring 6.x 和 Spring Boot 3.x ,Spring Cloud 2022.X最低支持的就是 Java 17。
1.增強的偽隨機數(shù)生成器
JDK 17 之前,我們可以借助 Random、ThreadLocalRandom和SplittableRandom來生成隨機數(shù)。不過,這 3 個類都各有缺陷,且缺少常見的偽隨機算法支持。
Java 17 為偽隨機數(shù)生成器 (pseudorandom number generator,RPNG,又稱為確定性隨機位生成器)增加了新的接口類型和實現(xiàn),使得開發(fā)者更容易在應(yīng)用程序中互換使用各種 PRNG 算法。
RPNGopen in new window?用來生成接近于絕對隨機數(shù)序列的數(shù)字序列。一般來說,PRNG 會依賴于一個初始值,也稱為種子,來生成對應(yīng)的偽隨機數(shù)序列。只要種子確定了,PRNG 所生成的隨機數(shù)就是完全確定的,因此其生成的隨機數(shù)序列并不是真正隨機的。
使用示例:
RandomGeneratorFactory<RandomGenerator>?l128X256MixRandom =?RandomGeneratorFactory.of("L128X256MixRandom");
// 使用時間戳作為隨機數(shù)種子
RandomGenerator?randomGenerator =?l128X256MixRandom.create(System.currentTimeMillis());
// 生成隨機數(shù)
randomGenerator.nextInt(10));
2.棄用 Applet API 以進行刪除
Applet API 用于編寫在 Web 瀏覽器端運行的 Java 小程序,很多年前就已經(jīng)被淘汰了,已經(jīng)沒有理由使用了。
Applet API 在 Java 9 時被標(biāo)記棄用(JEP 289open in new window),但不是為了刪除。
3.刪除遠程方法調(diào)用激活機制
刪除遠程方法調(diào)用 (RMI) 激活機制,同時保留 RMI 的其余部分。RMI 激活機制已過時且不再使用。
4.密封類(轉(zhuǎn)正)
密封類由 JEP 360open in new window?提出預(yù)覽,集成到了 Java 15 中。在 JDK 16 中, 密封類得到了改進(更加嚴(yán)格的引用檢查和密封類的繼承關(guān)系),由 JEP 397open in new window?提出了再次預(yù)覽。
5.刪除實驗性的 AOT 和 JIT 編譯器
在 Java 9 的 JEP 295open in new window?,引入了實驗性的提前 (AOT) 編譯器,在啟動虛擬機之前將 Java 類編譯為本機代碼。
Java 17,刪除實驗性的提前 (AOT) 和即時 (JIT) 編譯器,因為該編譯器自推出以來很少使用,維護它所需的工作量很大。保留實驗性的 Java 級 JVM 編譯器接口 (JVMCI),以便開發(fā)人員可以繼續(xù)使用外部構(gòu)建的編譯器版本進行 JIT 編譯。
java18新特性
1.默認(rèn)字符集為 UTF-8
JDK 終于將 UTF-8 設(shè)置為默認(rèn)字符集。
在 Java 17 及更早版本中,默認(rèn)字符集是在 Java 虛擬機運行時才確定的,取決于不同的操作系統(tǒng)、區(qū)域設(shè)置等因素,因此存在潛在的風(fēng)險。就比如說你在 Mac 上運行正常的一段打印文字到控制臺的 Java 程序到了 Windows 上就會出現(xiàn)亂碼,如果你不手動更改字符集的話。
2.簡易的 Web 服務(wù)器
Java 18 之后,你可以使用 jwebserver
命令啟動一個簡易的靜態(tài) Web 服務(wù)器。
$ jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /cwd and subdirectories on 127.0.0.1 port 8000
URL: http://127.0.0.1:8000/
這個服務(wù)器不支持 CGI 和 Servlet,只限于靜態(tài)文件。
3.優(yōu)化 Java API 文檔中的代碼片段
在 Java 18 之前,如果我們想要在 Javadoc 中引入代碼片段可以使用 <pre>{@code ...}</pre>
。
<pre>{@code
lines of source code
}</pre>
<pre>{@code ...}</pre>
這種方式生成的效果比較一般。
在 Java 18 之后,可以通過 @snippet
標(biāo)簽來做這件事情。
/**
* The following code shows how to use {@code Optional.isPresent}:
* {@snippet :
* if (v.isPresent()) {
* System.out.println("v: " + v.get());
* }
* }
*/
@snippet
這種方式生成的效果更好且使用起來更方便一些。
4.使用方法句柄重新實現(xiàn)反射核心
Java 18 改進了 java.lang.reflect.Method
、Constructor
的實現(xiàn)邏輯,使之性能更好,速度更快。這項改動不會改動相關(guān) API ,這意味著開發(fā)中不需要改動反射相關(guān)代碼,就可以體驗到性能更好反射。
OpenJDK 官方給出了新老實現(xiàn)的反射性能基準(zhǔn)測試結(jié)果。
新老實現(xiàn)的反射性能基準(zhǔn)測試結(jié)果
5.互聯(lián)網(wǎng)地址解析 SPI
Java 18 定義了一個全新的 SPI(service-provider interface),用于主要名稱和地址的解析,以便 java.net.InetAddress
可以使用平臺之外的第三方解析器。
Java 19 新特性
1.虛擬線程(預(yù)覽)
虛擬線程(Virtual Thread-)是 JDK 而不是 OS 實現(xiàn)的輕量級線程(Lightweight Process,LWP),許多虛擬線程共享同一個操作系統(tǒng)線程,虛擬線程的數(shù)量可以遠大于操作系統(tǒng)線程的數(shù)量。
虛擬線程在其他多線程語言中已經(jīng)被證實是十分有用的,比如 Go 中的 Goroutine、Erlang 中的進程。
虛擬線程避免了上下文切換的額外耗費,兼顧了多線程的優(yōu)點,簡化了高并發(fā)程序的復(fù)雜,可以有效減少編寫、維護和觀察高吞吐量并發(fā)應(yīng)用程序的工作量。
2.結(jié)構(gòu)化并發(fā)(孵化)
JDK 19 引入了結(jié)構(gòu)化并發(fā),一種多線程編程方法,目的是為了通過結(jié)構(gòu)化并發(fā) API 來簡化多線程編程,并不是為了取代java.util.concurrent
,目前處于孵化器階段。
結(jié)構(gòu)化并發(fā)將不同線程中運行的多個任務(wù)視為單個工作單元,從而簡化錯誤處理、提高可靠性并增強可觀察性。也就是說,結(jié)構(gòu)化并發(fā)保留了單線程代碼的可讀性、可維護性和可觀察性。
結(jié)構(gòu)化并發(fā)的基本 API 是StructuredTaskScopeopen in new window。StructuredTaskScope
支持將任務(wù)拆分為多個并發(fā)子任務(wù),在它們自己的線程中執(zhí)行,并且子任務(wù)必須在主任務(wù)繼續(xù)之前完成。
try (var scope = new StructuredTaskScope<Object>()) {
// 使用fork方法派生線程來執(zhí)行子任務(wù)
Future<Integer> future1 = scope.fork(task1);
Future<String> future2 = scope.fork(task2);
// 等待線程完成
scope.join();
// 結(jié)果的處理可能包括處理或重新拋出異常
... process results/exceptions ...
} // close
結(jié)構(gòu)化并發(fā)非常適合虛擬線程,虛擬線程是 JDK 實現(xiàn)的輕量級線程。許多虛擬線程共享同一個操作系統(tǒng)線程,從而允許非常多的虛擬線程。
Java 20 新特性
1.作用域值(第一次孵化)
作用域值(Scoped Values)它可以在線程內(nèi)和線程間共享不可變的數(shù)據(jù),優(yōu)于線程局部變量,尤其是在使用大量虛擬線程時。
final static ScopedValue<...> V = new ScopedValue<>();
// In some method
ScopedValue.where(V, <value>)
.run(() -> { ... V.get() ... call methods ... });
// In a method called directly or indirectly from the lambda expression
... V.get() ...
作用域值允許在大型程序中的組件之間安全有效地共享數(shù)據(jù),而無需求助于方法參數(shù)。
java21新特性
待補充
JDK21,將于2023年9月正式發(fā)布
官網(wǎng)已經(jīng)給出的新特性:
?JDK 21
三、其他
因為涉及特性較多,以上文章根據(jù)網(wǎng)絡(luò)上已有的文章,oracle官方文檔和自己的見解進行了再次整理,以下是參考較多的文章:文章來源:http://www.zghlxwxcb.cn/news/detail-834313.html
Java 20 新特性概覽 | JavaGuide(Java面試 + 學(xué)習(xí)指南)文章來源地址http://www.zghlxwxcb.cn/news/detail-834313.html
到了這里,關(guān)于JDK8,JDK11,JDK17,JDK21及中間版本主要更新特性的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!