關(guān)于jdk9、jdk10、jdk11、jdk12、jdk13新特性說明
我們絕大部分人估計(jì)都還在用著jdk8,12其實(shí)是一個(gè)非LTS(long time support)版本,而11與8一樣是LTS版,意味著下個(gè)通用的版本將從8直接到11,畢竟11包含了9和10的所有新特性,因此9和10估計(jì)就直接被廢棄啦。
不過9、10、11、12面向開發(fā)者的新特性其實(shí)并不是很多,大部分都是一些優(yōu)化、收集器加強(qiáng)以及增加了一些新功能等等
而我們開發(fā)人員最為關(guān)注的肯定是對(duì)我們搬磚有用的特性,雖然可能還用不太上,但這邊還是先記錄一下從jdk9-12的新特性:
jdk9新特性
1、集合加強(qiáng)
jdk9為所有集合(List/Set/Map)都增加了of和copyOf方法,用來創(chuàng)建不可變集合,即一旦創(chuàng)建就無法再執(zhí)行添加、刪除、替換、排序等操作,否則將報(bào)java.lang.UnsupportedOperationException異常。
一般在特定場(chǎng)景下用還是可以的,不過如果引用了guava庫(kù)的話推薦還是使用guava把hhhh,例子如下:
List?strs?=?List.of("Hello",?"World"); List?strsCopy =?List. copyOf(strs); Set?strs?=?Set.of("Hello",?"World"); Map?maps?=?Map.of("Hello",?1,?"World",?2);
2、私有接口方法
jdk8提供了接口的默認(rèn)方法(default)和靜態(tài)方法,打破了之前接口只能定義方法而不能存在行為。
jdk9則是允許接口定義私有方法,私有方法可以作為通用方法放在默認(rèn)方法中調(diào)用,不過實(shí)際中并無多大用處,至少對(duì)我來說。
3、垃圾收集機(jī)制
jdk9把G1作為默認(rèn)的垃圾收集器實(shí)現(xiàn),替換了jdk7和jdk8的默認(rèn)垃圾收集器實(shí)現(xiàn):Parallel Scavenge(新生代)+Parallel Old(老年代)。
4、I/O流加強(qiáng)
java.io.InputStream 中增加了新的方法來讀取和復(fù)制 InputStream 中包含的數(shù)據(jù):
readAllBytes
:讀取 InputStream 中的所有剩余字節(jié)readNBytes
: 從 InputStream 中讀取指定數(shù)量的字節(jié)到數(shù)組中transferTo
:讀取 InputStream 中的全部字節(jié)并寫入到指定的 OutputStream 中
5、JShell工具
jdk9引入了jshell這個(gè)交互性工具,讓Java也可以像腳本語言一樣來運(yùn)行,可以從控制臺(tái)啟動(dòng) jshell ,在 jshell 中直接輸入表達(dá)式并查看其執(zhí)行結(jié)果。
當(dāng)需要測(cè)試一個(gè)方法的運(yùn)行效果,或是快速的對(duì)表達(dá)式進(jìn)行求值時(shí),jshell 都非常實(shí)用。
舉個(gè)例子:
jdk10新特性
1、局部變量類型推斷
局部變量類型推斷可以說是jdk10中最值得注意的特性,這是Java語言開發(fā)人員為了簡(jiǎn)化Java應(yīng)用程序的編寫而采取的又一步,舉個(gè)例子:
原先我們需要這么定義一個(gè)list
List<String> list = new ArrayList<>();
使用局部類型推斷var關(guān)鍵詞定義
var list = new ArrayList<String>();
不過局部變量類型推斷僅僅適用在:
有初始化值的局部變量
增強(qiáng) for 循環(huán)中的索引
傳統(tǒng) for 循環(huán)中聲明的局部變量
Oracle 的 Java 團(tuán)隊(duì)申明,以下不支持局部變量類型推斷:
方法參數(shù)
構(gòu)造函數(shù)參數(shù)
方法返回類型
字段
catch 代碼塊(或任何其他類型的變量聲明)
2、線程本地握手
jdk10將引入一種在線程上執(zhí)行回調(diào)的新方法,因此這將會(huì)很方便能停止單個(gè)線程而不是停止全部線程或者一個(gè)都不停。說實(shí)話并不是很懂是什么意思...
3、GC改進(jìn)和內(nèi)存管理
jdk10中有2個(gè)JEP專門用于改進(jìn)當(dāng)前的垃圾收集元素。
第一個(gè)垃圾收集器接口是(JEP 304),它將引入一個(gè)純凈的垃圾收集器接口,以幫助改進(jìn)不同垃圾收集器的源代碼隔離。
預(yù)定用于Java 10的第二個(gè)JEP是針對(duì)G1的并行完全GC(JEP 307),其重點(diǎn)在于通過完全GC并行來改善G1最壞情況的等待時(shí)間。
G1是Java 9中的默認(rèn)GC,并且此JEP的目標(biāo)是使G1平行。
jdk11新特性
1、字符串加強(qiáng)
// 判斷字符串是否為空白 " ".isBlank(); // true // 去除首尾空格 " Javastack ".strip(); // "Javastack" // 去除尾部空格? " Javastack ".stripTrailing();? // 去除首部空格? " Javastack ".stripLeading(); // "Javastack " // 復(fù)制字符串 "Java".repeat(3); // "JavaJavaJava" // 行數(shù)統(tǒng)計(jì) "A\nB\nC".lines().count(); // 3
2、HttClient Api
這是 Java 9 開始引入的一個(gè)處理 HTTP 請(qǐng)求的的孵化 HTTP Client API,該 API 支持同步和異步,而在 Java 11 中已經(jīng)為正式可用狀態(tài),你可以在java.net包中找到這個(gè) Api
3、用于 Lambda 參數(shù)的局部變量語法
用于 Lambda 參數(shù)的局部變量語法簡(jiǎn)單來說就是支持類型推導(dǎo):
var x = new A(); for (var x : xs) { ... } try (var x = ...) { ... } catch ...
4、ZGC
從JDK 9開始,JDK使用G1作為默認(rèn)的垃圾回收器。G1可以說是GC的一個(gè)里程碑,G1之前的GC回收,還是基于固定的內(nèi)存區(qū)域,而G1采用了一種“細(xì)粒度”的內(nèi)存管理策略,不在固定的區(qū)分內(nèi)存區(qū)域?qū)儆趕urviors、eden、old,而我們不需要再去對(duì)于年輕代使用一種回收策略,老年代使用一種回收策略,取而代之的是一種整體的內(nèi)存回收策略。這種回收策略在我們當(dāng)下cpu、內(nèi)存、服務(wù)規(guī)模都越來越大的情況下提供了更好的表現(xiàn),而這一代ZGC更是有了突破性的進(jìn)步。
從原理上來理解,ZGC可以看做是G1之上更細(xì)粒度的內(nèi)存管理策略。由于內(nèi)存的不斷分配回收會(huì)產(chǎn)生大量的內(nèi)存碎片空間,因此需要整理策略防止內(nèi)存空間碎片化,在整理期間需要將對(duì)于內(nèi)存引用的線程邏輯暫停,這個(gè)過程被稱為"Stop the world"。只有當(dāng)整理完成后,線程邏輯才可以繼續(xù)運(yùn)行,一般而言,主要有如下幾種方式優(yōu)化"Stop the world":
- 使用多個(gè)線程同時(shí)回收(并行回收)
- 回收過程分為多次停頓(增量回收)
- 在程序運(yùn)行期間回收,不需要停頓或只停頓很短時(shí)間(并發(fā)回收)
- 只回收內(nèi)存而不整理內(nèi)存
ZGC主要采用的是并發(fā)回收的策略,相較于G1 ZGC最主要的提升是使用Load Barrier技術(shù)實(shí)現(xiàn),引用R大對(duì)于ZGC的評(píng)價(jià):
與標(biāo)記對(duì)象的傳統(tǒng)算法相比,ZGC在指針上做標(biāo)記,在訪問指針時(shí)加入Load Barrier(讀屏障),比如當(dāng)對(duì)象正被GC移動(dòng),指針上的顏色就會(huì)不對(duì),這個(gè)屏障就會(huì)先把指針更新為有效地址再返回,也就是,永遠(yuǎn)只有單個(gè)對(duì)象讀取時(shí)有概率被減速,而不存在為了保持應(yīng)用與GC一致而粗暴整體的Stop The World。
jdk12新特性
1、Switch Expressions
這是一個(gè)為開發(fā)者準(zhǔn)備的特性,我們可以利用具體代碼快速了解一下,下面是傳統(tǒng) statement 形式的 switch 語法:
switch (day) { case MONDAY: case FRIDAY: case SUNDAY: System.out.println(6); break; case TUESDAY: System.out.println(7); break; case THURSDAY: case SATURDAY: System.out.println(8); break; case WEDNESDAY: System.out.println(9); break; }
如果有編碼經(jīng)驗(yàn),你一定知道,switch 語句如果漏寫了一個(gè) break,那么邏輯往往就跑偏了,這種方式既繁瑣,又容易出錯(cuò)。
如果換成 switch 表達(dá)式,Pattern Matching 機(jī)制能夠自然地保證只有單一路徑會(huì)被執(zhí)行,請(qǐng)看下面的代碼示例:
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); }
更進(jìn)一步,下面的表達(dá)式,為我們提供了優(yōu)雅地表達(dá)特定場(chǎng)合計(jì)算邏輯的方式
int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6; case TUESDAY -> 7; case THURSDAY, SATURDAY -> 8; case WEDNESDAY -> 9; };
Switch Expressions 或者說起相關(guān)的 Pattern Matching 特性,為我們提供了勾勒出了 Java 語法進(jìn)化的一個(gè)趨勢(shì),將開發(fā)者從復(fù)雜繁瑣的低層次抽象中逐漸解放出來,以更高層次更優(yōu)雅的抽象,既降低代碼量,又避免意外編程錯(cuò)誤的出現(xiàn),進(jìn)而提高代碼質(zhì)量和開發(fā)效率。
2、Shenandoah GC
新增了一個(gè)名為 Shenandoah 的 GC 算法,通過與正在運(yùn)行的 Java 線程同時(shí)進(jìn)行 evacuation 工作來減少 GC 暫停時(shí)間。
使用 Shenandoah 的暫停時(shí)間與堆大小無關(guān),這意味著無論堆是 200 MB 還是 200 GB,都將具有相同的暫停時(shí)間。
JDK13新特性
JDK13于9月17日正式發(fā)布。目前該版本包含的特性已經(jīng)全部固定,主要包含以下五個(gè):
下面來逐一介紹下這五個(gè)重要的特性。
Dynamic CDS Archives
這一特性是在JEP310:Application Class-Data Sharing基礎(chǔ)上擴(kuò)展而來的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。
那么,這個(gè)JEP310是個(gè)啥東西呢?
我們知道在同一個(gè)物理機(jī)/虛擬機(jī)上啟動(dòng)多個(gè)JVM時(shí),如果每個(gè)虛擬機(jī)都單獨(dú)裝載自己需要的所有類,啟動(dòng)成本和內(nèi)存占用是比較高的。所以Java團(tuán)隊(duì)引入了CDS的概念,通過把一些核心類在每個(gè)JVM間共享,每個(gè)JVM只需要裝載自己的應(yīng)用類,啟動(dòng)時(shí)間減少了,另外核心類是共享的,所以JVM的內(nèi)存占用也減少了。
CDS 只能作用于 Boot Class Loader 加載的類,不能作用于 App Class Loader 或者自定義的 Class Loader 加載的類。
在 Java 10 中,則將 CDS 擴(kuò)展為 AppCDS,顧名思義,AppCDS 不止能夠作用于 Boot Class Loader了,App Class Loader 和自定義的 Class Loader 也都能夠起作用,大大加大了 CDS 的適用范圍。也就說開發(fā)自定義的類也可以裝載給多個(gè)JVM共享了。
Java 10中包含的JEP310的通過跨不同Java進(jìn)程共享公共類元數(shù)據(jù)來減少了內(nèi)存占用和改進(jìn)了啟動(dòng)時(shí)間。
但是,JEP310中,使用AppCDS的過程還是比較復(fù)雜的,需要有三個(gè)步驟:
這一次的JDK 13中的JEP 350 ,在JEP310的基礎(chǔ)上,又做了一些擴(kuò)展。允許在Java應(yīng)用程序執(zhí)行結(jié)束時(shí)動(dòng)態(tài)歸檔類,歸檔類將包括默認(rèn)的基礎(chǔ)層 CDS(class data-sharing)存檔中不存在的所有已加載的應(yīng)用程序類和庫(kù)類。
也就是說,在Java 13中再使用AppCDS的時(shí)候,就不在需要這么復(fù)雜了。
ZGC: Uncommit Unused Memory
在討論這個(gè)問題之前,想先問一個(gè)問題,JVM的GC釋放的內(nèi)存會(huì)還給操作系統(tǒng)嗎?
GC后的內(nèi)存如何處置,其實(shí)是取決于不同的垃圾回收器的。因?yàn)榘褍?nèi)存還給OS,意味著要調(diào)整JVM的堆大小,這個(gè)過程是比較耗費(fèi)資源的。
在JDK 11中,Java引入了ZGC,這是一款可伸縮的低延遲垃圾收集器,但是當(dāng)時(shí)只是實(shí)驗(yàn)性的。并且,ZGC釋放的內(nèi)存是不會(huì)還給操作系統(tǒng)的。
而在Java 13中,JEP 351再次對(duì)ZGC做了增強(qiáng),本次 ZGC 可以將未使用的堆內(nèi)存返回給操作系統(tǒng)。之所以引入這個(gè)特性,是因?yàn)槿缃裼泻芏鄨?chǎng)景中內(nèi)存是比較昂貴的資源,在以下情況中,將內(nèi)存還給操作系統(tǒng)還是很有必要的:
- 1、那些需要根據(jù)使用量付費(fèi)的容器
- 2、應(yīng)用程序可能長(zhǎng)時(shí)間處于空閑狀態(tài)并與許多其他應(yīng)用程序共享或競(jìng)爭(zhēng)資源的環(huán)境。
- 3、應(yīng)用程序在執(zhí)行期間可能有非常不同的堆空間需求。例如,啟動(dòng)期間所需的堆可能大于稍后在穩(wěn)定狀態(tài)執(zhí)行期間所需的堆。
Reimplement the Legacy Socket API
使用易于維護(hù)和調(diào)試的更簡(jiǎn)單、更現(xiàn)代的實(shí)現(xiàn)替換 java.net.Socket 和 java.net.ServerSocket API。
java.net.Socket和java.net.ServerSocket的實(shí)現(xiàn)非常古老,這個(gè)JEP為它們引入了一個(gè)現(xiàn)代的實(shí)現(xiàn)?,F(xiàn)代實(shí)現(xiàn)是Java 13中的默認(rèn)實(shí)現(xiàn),但是舊的實(shí)現(xiàn)還沒有刪除,可以通過設(shè)置系統(tǒng)屬性jdk.net.usePlainSocketImpl來使用它們。
運(yùn)行一個(gè)實(shí)例化Socket和ServerSocket的類將顯示這個(gè)調(diào)試輸出。這是默認(rèn)的(新的).
上面輸出的sun.nio.ch.NioSocketImpl就是新提供的實(shí)現(xiàn)。
如果使用舊的實(shí)現(xiàn)也是可以的(指定參數(shù)jdk.net.usePlainSocketImpl):
上面的結(jié)果中,舊的實(shí)現(xiàn)java.net.PlainSocketImpl被用到了。
Switch Expressions (Preview)
在JDK 12中引入了Switch表達(dá)式作為預(yù)覽特性。JEP 354修改了這個(gè)特性,它引入了yield語句,用于返回值。這意味著,switch表達(dá)式(返回值)應(yīng)該使用yield, switch語句(不返回值)應(yīng)該使用break。
在以前,我們想要在switch中返回內(nèi)容,還是比較麻煩的,一般語法如下:
在JDK13中使用以下語法:
或者
在這之后,switch中就多了一個(gè)關(guān)鍵字用于跳出switch塊了,那就是yield,他用于返回一個(gè)值。和return的區(qū)別在于:return會(huì)直接跳出當(dāng)前循環(huán)或者方法,而yield只會(huì)跳出當(dāng)前switch塊。
Text Blocks (Preview)
在JDK 12中引入了Raw String Literals特性,但在發(fā)布之前就放棄了。這個(gè)JEP在引入多行字符串文字(text block)在意義上是類似的。
text block,文本塊,是一個(gè)多行字符串文字,它避免了對(duì)大多數(shù)轉(zhuǎn)義序列的需要,以可預(yù)測(cè)的方式自動(dòng)格式化字符串,并在需要時(shí)讓開發(fā)人員控制格式。
我們以前從外部copy一段文本串到Java中,會(huì)被自動(dòng)轉(zhuǎn)義,如有一段以下字符串:
將其復(fù)制到Java的字符串中,會(huì)展示成以下內(nèi)容:
使用“”“作為文本塊的開始符合結(jié)束符,在其中就可以放置多行的字符串,不需要進(jìn)行任何轉(zhuǎn)義??雌饋砭褪智逅?。
如常見的SQL語句:
看起來就比較直觀,清爽了。
JDK13中包含的5個(gè)特性,能夠改變開發(fā)者的編碼風(fēng)格的主要有Text Blocks和Switch Expressions兩個(gè)新特性,但是這兩個(gè)特性還處于預(yù)覽階段。
而且,JDK13并不是LTS(長(zhǎng)期支持)版本,如果你正在使用Java 8(LTS)或者Java 11(LTS),暫時(shí)可以不必升級(jí)到Java 13.
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用Java實(shí)現(xiàn)查看線程的運(yùn)行狀態(tài)(附源碼)
在現(xiàn)代 Java 應(yīng)用中,線程的運(yùn)行狀態(tài)對(duì)于排查問題和優(yōu)化性能具有至關(guān)重要的作用,本文將使用Java編寫一個(gè)查看線程運(yùn)行狀態(tài)的工具,有需要的可以了解下2025-03-03使用InputStream的available()能否用來判斷當(dāng)前流是否讀取到文件
這篇文章主要介紹了使用InputStream的available()能否用來判斷當(dāng)前流是否讀取到文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06kafka分布式消息系統(tǒng)基本架構(gòu)及功能詳解
這篇文章主要為大家介紹了kafka分布式消息系統(tǒng)基本架構(gòu)及功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03springboot引用kettle實(shí)現(xiàn)對(duì)接oracle數(shù)據(jù)的示例代碼
這篇文章主要介紹了springboot引用kettle實(shí)現(xiàn)對(duì)接oracle數(shù)據(jù),其實(shí)kettle集成到springboot里面沒有多少代碼,這個(gè)功能最主要的還是ktr文件的編寫,只要ktr編寫好了,放到指定文件夾下,寫個(gè)定時(shí)任務(wù)就完事了,需要的朋友可以參考下2022-12-12Spring Boot創(chuàng)建非可執(zhí)行jar包的實(shí)例教程
這篇文章主要介紹了Spring Boot創(chuàng)建非可執(zhí)行jar包的實(shí)例教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02解決IDEA創(chuàng)建maven項(xiàng)目時(shí)pom.xml沒有變藍(lán)的問題
這篇文章主要介紹了解決IDEA創(chuàng)建maven項(xiàng)目時(shí)pom.xml沒有變藍(lán)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08