DK19都出來了~是時候梳理JDK的各個版本的特性「JDK9特性講解」
一、JDK版本特性
??JAVA8 及之前,版本都是特性驅(qū)動的版本更新,就是有重大的特性產(chǎn)生,然后進(jìn)行更新。
??JAVA9開始,JDK開始以時間為驅(qū)動進(jìn)行更新,以半年為周期,到時即更新,三年出一個長期支持版,其他都是短暫的版本。
??目前的長期支持版有 JAVA8 JAVA11 和JAVA17,這些版本大家注意在將來的工作中使用的概率更高,也就是說我們將來研發(fā),使用JAVA11 ,然后使用JAVA17 是必然的,只是一個時間的問題。
??新的長期支持版每三年發(fā)布一次,根據(jù)后續(xù)的發(fā)布計劃,下一個長期支持的版本JAVA17于2021年發(fā)布。
環(huán)境準(zhǔn)備:
下載JDK,可以通過https://www.injdk.cn/ 去下載各種不同版本的JDK, 因?yàn)镴DK是向下兼容的,所以我們使用一個較新的JDK,就可以去測試和學(xué)習(xí)從9-最新所有版本的新特征了,我們這里以安裝openjdk19為例,下載安裝JDK19的壓縮包。
下載后可以解壓到我們磁盤的任意位置,我這里的位置是 D:\software\openjdk-19.0.1_windows-x64_bin\jdk-19.0.1。
在IDEA中創(chuàng)建項目。可以選擇對應(yīng)的JDK。
當(dāng)然,也可以在項目創(chuàng)建完畢之后,更換JDK為19。
二、JDK9特性講解
1. JDK9特性概述
經(jīng)過4次推遲,歷經(jīng)曲折的Java9最終在2017年9月21日發(fā)布。因?yàn)槔锩婕尤氲哪K化系統(tǒng),在最初設(shè)想的時候并沒有想過那么復(fù)雜,花費(fèi)的時間超出預(yù)估時間。距離java8大約三年時間。 ??Java 9提供了超過150項新功能特性,包括備受期待的模塊化系統(tǒng)、可交互的REPL工具: jshell, JDK編譯工具,語法層面的改變:Java公共API和私有代碼,以及安全增強(qiáng)、擴(kuò)展提升、性能管理改善等。可以說Java 9是一個龐大的系統(tǒng)工程,完全做了一個整體改變。 ?
但是這個巨大改變的功勞,都給了java11了,目前oracle對8,11都長期支持,9,10不支持了,只能從歷史版本(??http://jdk.java.net/)中下載,Java?? 11 將會獲得 Oracle 提供的長期支持服務(wù),直至2026年9月。
從Java9這個版本開始,Java 的計劃發(fā)布周期是6個月,下一個Java的主版本將于2018年3月發(fā)布,命名為Java18.3(java10), 緊接著再過六個月將發(fā)布Java18.9(java11). ??這意味著Java的更新從傳統(tǒng)的以特性驅(qū)動的發(fā)布周期,轉(zhuǎn)變?yōu)橐詴r間驅(qū)動的(6個月為周期)發(fā)布模式**(更快的時間周期,oracle的理念就是小步快跑,快速迭代,像IBM(DB2數(shù)據(jù)庫,保守型內(nèi)部測試才投入市場)),并逐步的將Oracle JDK原商業(yè)特性進(jìn)行開源。針對企業(yè)客戶的需求,Oracle將以三年為周期發(fā)布長期支持版本(long term support)。
2. JDK9的改變
JDK9的具體變化在下面的思維導(dǎo)圖中呈現(xiàn):
官方提供的新特性的列表:
https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6。
openJDK 可參考源碼。
http://openjdk.java.net/projects/jdk9/。
在線 OracleJDK Documentation 在線文檔。
https://docs.oracle.com/javase/9/。
3. JDK和JRE目錄變化
??然后我們來看看JDK和JRE在JDK8和JDK9的差異。
目錄作用介紹:
bin 包含命令行開發(fā)和調(diào)試工具 如javac jar javadoc。
include 包含編譯本地代碼時使用的c/c++頭部文件。
lib 包含JDK工具的幾個jar和其他類型的文件,他有一個tools.jar文件,其中含javac編譯器的java類。
jre/bin目錄 包含基本指令,如java指令,在windows平臺上,它包含系統(tǒng)的運(yùn)行時動態(tài)鏈接。
jre/lib包含用戶可編輯的配置文件,如properties和.policy文件,包含幾個jar文件,rt.jar文件包含運(yùn)行時的java類和資源文件。
目錄介紹:
- bin 包含所有指令,在windows平臺上,他繼續(xù)包含系統(tǒng)的運(yùn)行時動態(tài)鏈接。
- conf目錄 包含用戶可編輯的配置文件,例如之前位于jre/lib目錄中的.properties和policy。
- includes 包含在以前編譯本地代碼時使用c/c++頭文件,他只存在于JDK中。
- jmods 包含JMOD格式的平臺模塊,創(chuàng)建自定義運(yùn)行時映像需要他,它只存在于jdk中。
- legal 法律聲明。
- lib 包含非windows平臺上的動態(tài)鏈接本地庫,其子目錄和文件不應(yīng)由開發(fā)人員直接編譯或使用。
- 從9開始以后的JDK目錄結(jié)構(gòu)都是如此。
4. 語法層次改變
4.1 鉆石操作符號語法升級
鉆石操作符,就是我們泛型使用的符號<>。
JAVA8 中,匿名內(nèi)部類不能使用鉆石操作符,如下代碼在JAVA8 中是報錯的,匿名內(nèi)部類這里不支持泛型推斷,重寫的方法不明確泛型。
這里匿名內(nèi)部類中的<>號里必須要和前面的聲明保持一致,不能空著不寫,這樣重寫的方法就根據(jù)匿名內(nèi)部類的泛型。
但是這種寫法在JAVA9 中就允許了。
而且在JAVA9中,匿名內(nèi)部類的語法不僅僅可以用于接口和抽象類,普通類也可以通過匿名內(nèi)部類寫法,在某個實(shí)例上完成對某個方法的重寫。
4.2 try結(jié)構(gòu)語法升級
普通的try catch finally語句 要釋放的資源可以放到finally語句塊中。
JAVA 8中已經(jīng)對try語法進(jìn)行了升級,可以將要釋放的資源放到try后面的小括號中,這樣就不用通過finally語句塊釋放資源了,但是要求執(zhí)行后必須關(guān)閉的資源一定要放在try子句中進(jìn)行初始化,否則編譯不通過. 下面的案例中,reader必須放在try后面的小括號中進(jìn)行初始化。
JAVA 9 資源的關(guān)閉操作,我們可以在try子句中使用已經(jīng)初始化的資源但是此時的資源必須 是final修飾的,final可以省略不寫。
4.3 下劃線命名標(biāo)識符的使用限制
標(biāo)識符命名組成:字母,數(shù)字,下劃線,美元符。
JAVA8 中,可以使用一個 _ 作為標(biāo)識符的命名。
JAVA9 中,就不可以使用一個_ 作為標(biāo)識符的命名了,不通過編譯,但是標(biāo)識符中仍然可以使用_,必須配合其他內(nèi)容。
小細(xì)節(jié):注意一下即可,一般也沒人直接單獨(dú)用一個_ 作為標(biāo)識符的命名。
5. API層次的改變
5.1 接口中的私有方法
??接口中的設(shè)計使用在JDK789中都有相關(guān)的變化的。
JAVA7 中,接口只能有抽象方法。
JAVA8 中,接口中static(靜態(tài)不可重寫)和default(可以重寫)修飾的方法可以擁有方法體。
JAVA9 中,接口中可以使用private修飾方法,并擁有方法體,但是接口中的成員變量仍然不能用private修飾。
感覺: 接口中的代碼越來越靠近抽象類,但是仍然是支持多繼承的。
代碼案例
5.2 String底層存儲結(jié)構(gòu)變化
??JAVA8 中的String源碼,String類內(nèi)部維護(hù)的是一個final修飾的私有char數(shù)組,說明String的底層是通過char數(shù)組存儲字符串的。
??JAVA9 中String的源碼,String類內(nèi)部維護(hù)的是一個final修飾的私有byte數(shù)組,說明String的底層是通過byte數(shù)組存儲字符串的.
這么調(diào)整的原因:
大多數(shù)String對象只包含latin-1字符。 這樣的字符只需要一個字節(jié)的存儲空間,因此這樣的String對象的內(nèi)部字符數(shù)組中有一半的空間沒有使用 , 我們建議將String類的內(nèi)部表示形式從UTF-16字符數(shù)組更改為一個字節(jié)數(shù)組加上一個結(jié)束編碼標(biāo)志字段。
5.3 Stream新增4個API
??JAVA9 中,Stream接口添加了4個新方法,takeWhile,dropWhile,ofNullable,還有一個iterate 方法的新重載方法,可以通過一個Predicate來指定什么時候結(jié)束迭代。
??除了Stream本身的擴(kuò)展,Optional和Stream之間的結(jié)合也得到了改進(jìn),現(xiàn)在可以通過Optional的新方法將一個Optional對象轉(zhuǎn)換為一個Stream對象(可能是空的)。
5.4 InputStream新增transferTo方法
??InputStream新增transferTo方法,可以用來將數(shù)據(jù)直接傳輸?shù)絆utpuStream,這是在處理原始數(shù)據(jù)時非常常見的一種方法。
5.5 只讀集合創(chuàng)建
??JAVA8 要創(chuàng)建一個只讀,不可改變的集合,必須構(gòu)造和分配他,然后添加元素,然后再包裝成一個不可修的集合。
??放入數(shù)據(jù)后,然后要通過unmodifiableList才能讓集合變?yōu)橹蛔x集合,不能表達(dá)為單個的表達(dá)式。
JAVA9 通過集合工廠方法,創(chuàng)建一個只讀集合,只要通過新增的of方法即可完成創(chuàng)建。
上面是List接口的of方法, 同樣的,Set接口和Map接口下也新增了of方法,也是返回一個只讀集合。
6. 其他變化
6.1 模塊化
??談到Java9大家往往第一個想到的就是Jigsaw項目(后改名為Modularity)。眾所周知,Java已經(jīng)發(fā)展超過20年(95年最初發(fā)布),Java和相關(guān)生態(tài)在不斷豐富的同時也越來越暴露出一些問題。
Java運(yùn)行環(huán)境的膨脹和臃腫。每次JVM啟動的時候,至少會有30~ 60MB的內(nèi)存加載,主要原因是JVM需要加載rt.jar,不管其中的類是否被classloader加載,第一步整個jar都會被JVM加載到內(nèi)存當(dāng)中去(而模塊化可以根據(jù)模塊的需要加載程序運(yùn)行需要的class)。
當(dāng)代碼庫越來越大,創(chuàng)建復(fù)雜,盤根錯節(jié)的“意大利面條式代碼”的幾率呈指數(shù)級的增長。不同版本的類庫交叉依賴導(dǎo)致讓人頭疼的問題,這些都阻礙了Java 開發(fā)和運(yùn)行效率的提升。
很難真正地對代碼進(jìn)行封裝,而系統(tǒng)并沒有對不同部分(也就是JAR文件)之間的依賴關(guān)系有個明確的概念。每一個公共類都可以被類路徑之下任何其它的公共類所訪問到,這樣就會導(dǎo)致無意中使用了并不想被公開訪問的API。
??本質(zhì)上講,模塊化,就是在package外面包裹一層->>>說白了項目下有眾多 模塊 進(jìn)行項目管理,管理各個模塊,比如一個電商項目 下面有支付模塊 購物模塊,,,模塊跟模塊之間相互調(diào)用,這樣代碼就更安全,可以指定哪些暴露 哪些隱藏!
??模塊之間的可訪問性是所使用的模塊和使用模塊之間的雙向協(xié)議:模塊明確地使其公共類型可供其他模塊使用,而且使用這些公共類型的模塊明確聲明對第一個模塊的依賴,模塊中所有未導(dǎo)出的軟件包都是模塊的私有的,他們不能在模塊之外使用.之前做不到,現(xiàn)在可以考慮這個事了。
案例演示:
創(chuàng)建一個普通的Java項目;
然后在這個項目下準(zhǔn)備兩個模塊。
然后在JDK19Module1中添加一些類就可以了;
然后我們需要考慮如何在JDK19module2中使用這個類? 或者說是使用模塊1中的類,第一步,在兩個模塊的src下創(chuàng)建各自的module-info.java;
創(chuàng)建完畢的結(jié)構(gòu)為:
在JDK19Module1的module-info.java文件中。設(shè)置哪些包可以向外暴露;
然后在JDK19Module2的module-info.java中引入模塊2;
但是發(fā)現(xiàn)報錯了,原因是,我們要把模塊1添加為模塊2的運(yùn)行環(huán)境,具體操作如下:
project structure > modules > JDK19Module2>dependencies >>+module lib > JDK19Module1> apply >>ok。
這個是時候,我們在模塊2中就可以使用模塊1 中的類了。
6.2 可交互的REPL工具
??像Python和Scala 之類的語言早就有交互式編程環(huán)境REPL (read -evaluate - print -loop)了,以交互式的方式對語句和表達(dá)式進(jìn)行求值。開發(fā)者只需要輸入一些代碼,就可以在編譯前獲得對程序的反饋。而之前的Java 版本要想執(zhí)行代碼,必須創(chuàng)建文件、聲明類、提供測試方法方可實(shí)現(xiàn)。
要想實(shí)現(xiàn)REPL,需要一個命令:JShell命令(linux中是shell命令,java中的shell命令)。
??將環(huán)境變量配置為java9,就可以在控制命令臺使用jshell命令了:如果電腦上安裝了其他版本的JDK,環(huán)境變量也是其他版本,大家可以在dos上通過cd 切換到指定版本的bin目錄下,就可以使用該版本的jshell了。
簡單的輸出語句;
變量定義:
方法定義和調(diào)用;
導(dǎo)包處理;
??其實(shí)jshell中有默認(rèn)的導(dǎo)入一些包(除了java.lang之外,以下包也可以直接用),可以直接使用不用導(dǎo)包,查看有哪些:
常用命令;
上面操作的代碼關(guān)閉窗口后就消失了。如果我們需要持久化相關(guān)的代碼,也可以操作;
退出jshell?;