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