lecture:波哥
image.png
??JAVA8 及之前,版本都是特性驅動的版本更新,就是有重大的特性產生,然后進行更新
??JAVA9開始,JDK開始以時間為驅動進行更新,以半年為周期,到時即更新,三年出一個長期支持版,其他都是短暫的版本
??目前的長期支持版有 JAVA8 JAVA11 和JAVA17,這些版本大家注意在將來的工作中使用的概率更高,也就是說我們將來研發,使用JAVA11 ,然后使用JAVA17 是必然的,只是一個時間的問題
??新的長期支持版每三年發布一次,根據后續的發布計劃,下一個長期支持的版本JAVA17于2021年發布
環境準備:
下載JDK,可以通過https://www.injdk.cn/ 去下載各種不同版本的JDK, 因為JDK是向下兼容的,所以我們使用一個較新的JDK,就可以去測試和學習從9-最新所有版本的新特征了,我們這里以安裝openjdk19為例,下載安裝JDK19的壓縮包
image.png
下載后可以解壓到我們磁盤的任意位置,我這里的位置是 D:\software\openjdk-19.0.1_windows-x64_bin\jdk-19.0.1
image.png
在IDEA中創建項目。可以選擇對應的JDK
image.png
當然,也可以在項目創建完畢之后,更換JDK為19
??經過4次推遲,歷經曲折的Java9最終在2017年9月21日發布。因為里面加入的模塊化系統,在最初設想的時候并沒有想過那么復雜,花費的時間超出預估時間。距離java8大約三年時間。 ??Java 9提供了超過150項新功能特性,包括備受期待的模塊化系統、可交互的REPL工具: jshell, JDK編譯工具,語法層面的改變:Java公共API和私有代碼,以及安全增強、擴展提升、性能管理改善等。可以說Java 9是一個龐大的系統工程,完全做了一個整體改變。 ??但是這個巨大改變的功勞,都給了java11了,目前oracle對8,11都長期支持,9,10不支持了,只能從歷史版本(http://jdk.java.net/)中下載,Java 11 將會獲得 Oracle 提供的長期支持服務,直至2026年9月。 ??從Java9這個版本開始,Java 的計劃發布周期是6個月,下一個Java的主版本將于2018年3月發布,命名為Java18.3(java10), 緊接著再過六個月將發布Java18.9(java11). ??這意味著Java的更新從傳統的以特性驅動的發布周期,轉變為以時間驅動的(6個月為周期)發布模式**(更快的時間周期,oracle的理念就是小步快跑,快速迭代,像IBM(DB2數據庫,保守型內部測試才投入市場)),并逐步的將Oracle JDK原商業特性進行開源。針對企業客戶的需求,Oracle將以三年為周期發布長期支持版本(long term support)
JDK9的具體變化在下面的思維導圖中呈現:
image.png
官方提供的新特性的列表
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/
??然后我們來看看JDK和JRE在JDK8和JDK9的差異
image.png
目錄作用介紹:
bin 包含命令行開發和調試工具 如javac jar javadoc
include 包含編譯本地代碼時使用的c/c++頭部文件
lib 包含JDK工具的幾個jar和其他類型的文件,他有一個tools.jar文件,其中含javac編譯器的java類
jre/bin目錄 包含基本指令,如java指令,在windows平臺上,它包含系統的運行時動態鏈接
jre/lib包含用戶可編輯的配置文件,如properties和.policy文件,包含幾個jar文件,rt.jar文件包含運行時的java類和資源文件
image.png
目錄介紹:
bin 包含所有指令,在windows平臺上,他繼續包含系統的運行時動態鏈接
conf目錄 包含用戶可編輯的配置文件,例如之前位于jre/lib目錄中的.properties和policy
includes 包含在以前編譯本地代碼時使用c/c++頭文件,他只存在于JDK中
jmods 包含JMOD格式的平臺模塊,創建自定義運行時映像需要他,它只存在于jdk中
legal 法律聲明
lib 包含非windows平臺上的動態鏈接本地庫,其子目錄和文件不應由開發人員直接編譯或使用
從9開始以后的JDK目錄結構都是如此
鉆石操作符,就是我們泛型使用的符號<>
JAVA8 中,匿名內部類不能使用鉆石操作符,如下代碼在JAVA8 中是報錯的,匿名內部類這里不支持泛型推斷,重寫的方法不明確泛型
image.png
這里匿名內部類中的<>號里必須要和前面的聲明保持一致,不能空著不寫,這樣重寫的方法就根據匿名內部類的泛型
image.png
但是這種寫法在JAVA9 中就允許了
image.png
而且在JAVA9中,匿名內部類的語法不僅僅可以用于接口和抽象類,普通類也可以通過匿名內部類寫法,在某個實例上完成對某個方法的重寫
public class Demo1 {
public static void main(String[] args) {
/*
* 匿名內部類僅僅在接口和抽象類上使用,作為一種快速的實現方式
* JAVA9中,普通類也可以借助這種語法形式實現對方法的快速臨時的重寫
* */
Person<String> person=new Person<>(){
@Override
public void eat(String s) {
super.eat(s);
}
};
person.eat("油條");
}
}
class Person<T>{
public void eat(T t){
System.out.println("Person eat");
}
}
普通的try catch finally語句 要釋放的資源可以放到finally語句塊中
public class Demo02 {
public static void main(String[] args) {
InputStreamReader reader=null;
try{
reader=new InputStreamReader(System.in);
int read=reader.read();
}catch (Exception e){
throw new RuntimeException(e);
}finally {
// 這里可以釋放資源
if(null !=reader){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
JAVA 8中已經對try語法進行了升級,可以將要釋放的資源放到try后面的小括號中,這樣就不用通過finally語句塊釋放資源了,但是要求執行后必須關閉的資源一定要放在try子句中進行初始化,否則編譯不通過. 下面的案例中,reader必須放在try后面的小括號中進行初始化
public static void main(String[] args) {
try( InputStreamReader reader=new InputStreamReader(System.in) ){
int read=reader.read();
}catch (Exception e){
throw new RuntimeException(e);
}
}
JAVA 9 資源的關閉操作,我們可以在try子句中使用已經初始化的資源但是此時的資源必須 是final修飾的,final可以省略不寫
// JAVA9 try語法升級
public void testb() throws FileNotFoundException {
// JAVA9 try catch finally語句塊
InputStreamReader isr=new InputStreamReader(new FileInputStream("d:/UserMapper.xml"));
OutputStreamWriter isw=new OutputStreamWriter(new FileOutputStream("d:/UserMapper1.xml"));
try( isr; isw){
isr.read();
}catch (Exception e){
e.printStackTrace();
}
}
標識符命名組成:字母,數字,下劃線,美元符
JAVA8 中,可以使用一個 _ 作為標識符的命名
image.png
JAVA9 中,就不可以使用一個_ 作為標識符的命名了,不通過編譯,但是標識符中仍然可以使用_,必須配合其他內容
image.png
小細節:注意一下即可,一般也沒人直接單獨用一個_ 作為標識符的命名
??接口中的設計使用在JDK789中都有相關的變化的。
JAVA7 中,接口只能有抽象方法
JAVA8 中,接口中static(靜態不可重寫)和default(可以重寫)修飾的方法可以擁有方法體
JAVA9 中,接口中可以使用private修飾方法,并擁有方法體,但是接口中的成員變量仍然不能用private修飾
感覺: 接口中的代碼越來越靠近抽象類,但是仍然是支持多繼承的
image.png
代碼案例
public class Demo4 {
// 接口,是一種規范和要求
// 實現多繼承
}
// java7 接口中的方法必須都是抽象的
interface Inter1 {
void methoda();
}
// java8接口可以定義static/default修飾的非抽象方法
interface Inter2 {
void methoda();
static void methodB() {
}
default void methodC() {
}
}
// java9 允許定義私有的非抽象方法
interface Inter3 {
void methoda();
static void methodB() {
}
default void methodC() {
methodD();
}
private void methodD() {
}
}
??JAVA8 中的String源碼,String類內部維護的是一個final修飾的私有char數組,說明String的底層是通過char數組存儲字符串的。
image.png
??JAVA9 中String的源碼,String類內部維護的是一個final修飾的私有byte數組,說明String的底層是通過byte數組存儲字符串的.
image.png
這么調整的原因:
大多數String對象只包含latin-1字符。 這樣的字符只需要一個字節的存儲空間,因此這樣的String對象的內部字符數組中有一半的空間沒有使用 , 我們建議將String類的內部表示形式從UTF-16字符數組更改為一個字節數組加上一個結束編碼標志字段
??JAVA9 中,Stream接口添加了4個新方法,takeWhile,dropWhile,ofNullable,還有一個iterate 方法的新重載方法,可以通過一個Predicate來指定什么時候結束迭代.
/**
* 測試Stream新增takeWhile方法
* takeWhile 從流中的頭開始取元素,直到不滿足條件為止
*/
public static void testTakeWhile(){
List<Integer> list=Arrays.asList(1, 89, 63, 45, 72, 65, 41, 65, 82, 35, 95, 100);
// 從頭開始取所有奇數,直到遇見一個偶數為止
list.stream().takeWhile(e-> e%2==1).forEach(System.out::println);
}
/**
* 測試Stream新增dropWhile方法
* dropWhile 從頭開始刪除滿足條件的數據,直到遇見第一個不滿足的位置,并保留剩余元素
*/
public static void testDropWhile(){
List<Integer> list=Arrays.asList(2, 86, 63, 45, 72, 65, 41, 65, 82, 35, 95, 100);
// 刪除流開頭所有的偶數,直到遇見奇數為止
list.stream().dropWhile(e-> e%2==0 ).forEach(System.out::println);
}
/**
* 測試Stream新增ofNullable方法
* ofNullable 允許創建Stream流時,只放入一個null
*/
public static void testOfNullable(){
// of方法獲取流 ,允許元素中有多個null值
Stream<Integer> stream1=Stream.of(10, 20, 30, null);
// 如果元素中只有一個null,是不允許的
Stream<Integer> stream2=Stream.of(null);
// JAVA9中,如果元素為null,返回的是一個空Stream,如果不為null,返回一個只有一個元素的Stream
Stream<Integer> stream3=Stream.ofNullable(null);
}
/**
* 測試Stream新增iterate方法
* iterate指定種子數,指定條件和迭代方式來獲取流
*/
public static void testNewIterate(){
//JAVA8通過 generate方法獲取一個Stream
Stream.generate(Math::random).limit(10).forEach(System.out::println);
//JAVA8 通過iterate獲取一個Stream
Stream.iterate(0,t-> t+2).limit(10).forEach(System.out::println);
//JAVA9通過重載iterate獲取Stream
Stream.iterate(0,t -> t<10,t-> t+1).forEach(System.out::println);
}
??除了Stream本身的擴展,Optional和Stream之間的結合也得到了改進,現在可以通過Optional的新方法將一個Optional對象轉換為一個Stream對象(可能是空的)
/**
* Optional類新增Stream方法,可以將一個Optional轉換為Stream
*/
public static void testOptionalStream(){
List<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,45,95,36,85,47);
Optional<List<Integer>> optional=Optional.ofNullable(list);
// 通過optional的Stream方法獲取一個Stream
Stream<List<Integer>> stream=optional.stream();
// 以為內部的每個元素也是一個List,通過flatMap方法,將內部的List轉換為Stream后再放入一個大Stream
stream.flatMap(x->x.stream()).forEach(System.out::println);
}
??InputStream新增transferTo方法,可以用來將數據直接傳輸到OutpuStream,這是在處理原始數據時非常常見的一種方法
InputStream inputStream=new FileInputStream("d:/aaa.txt");
OutputStream outputStream=new FileOutputStream("d:/bbb.txt");
try (inputStream;outputStream){
inputStream.transferTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
??JAVA8 要創建一個只讀,不可改變的集合,必須構造和分配他,然后添加元素,然后再包裝成一個不可修的集合.
List<String> list=new ArrayList<>();
list.add("Tom");
list.add("Jerry");
list.add("Mark");
list.add("Jhon");
list=Collections.unmodifiableList(list);
System.out.println(list);
??放入數據后,然后要通過unmodifiableList才能讓集合變為只讀集合,不能表達為單個的表達式
JAVA9 通過集合工廠方法,創建一個只讀集合,只要通過新增的of方法即可完成創建.
public static void main(String[] args) {
List<String> list=List.of("張三", "李四", "王五");
System.out.println(list);
list.set(0,"aaa");
System.out.println(list);
}
image.png
上面是List接口的of方法, 同樣的,Set接口和Map接口下也新增了of方法,也是返回一個只讀集合
??談到Java9大家往往第一個想到的就是Jigsaw項目(后改名為Modularity)。眾所周知,Java已經發展超過20年(95年最初發布),Java和相關生態在不斷豐富的同時也越來越暴露出一些問題:
??本質上講,模塊化,就是在package外面包裹一層->>>說白了項目下有眾多 模塊 進行項目管理,管理各個模塊,比如一個電商項目 下面有支付模塊 購物模塊,,,模塊跟模塊之間相互調用,這樣代碼就更安全,可以指定哪些暴露 哪些隱藏!
??模塊之間的可訪問性是所使用的模塊和使用模塊之間的雙向協議:模塊明確地使其公共類型可供其他模塊使用,而且使用這些公共類型的模塊明確聲明對第一個模塊的依賴,模塊中所有未導出的軟件包都是模塊的私有的,他們不能在模塊之外使用.之前做不到,現在可以考慮這個事了.
案例演示:
創建一個普通的Java項目
image.png
然后在這個項目下準備兩個模塊。
image.png
然后在JDK19Module1中添加一些類就可以了
image.png
然后我們需要考慮如何在JDK19module2中使用這個類? 或者說是使用模塊1中的類,第一步,在兩個模塊的src下創建各自的module-info.java
image.png
創建完畢的結構為:
image.png
在JDK19Module1的module-info.java文件中。設置哪些包可以向外暴露
image.png
然后在JDK19Module2的module-info.java中引入模塊2
image.png
但是發現報錯了,原因是,我們要把模塊1添加為模塊2的運行環境,具體操作如下
project structure > modules > JDK19Module2>dependencies >>+module lib > JDK19Module1> apply >>ok
image.png
這個是時候,我們在模塊2中就可以使用模塊1 中的類了
image.png
??像Python和Scala 之類的語言早就有交互式編程環境REPL (read -evaluate - print -loop)了,以交互式的方式對語句和表達式進行求值。開發者只需要輸入一些代碼,就可以在編譯前獲得對程序的反饋。而之前的Java 版本要想執行代碼,必須創建文件、聲明類、提供測試方法方可實現。
要想實現REPL,需要一個命令:JShell命令(linux中是shell命令,java中的shell命令)
image.png
??將環境變量配置為java9,就可以在控制命令臺使用jshell命令了:如果電腦上安裝了其他版本的JDK,環境變量也是其他版本,大家可以在dos上通過cd 切換到指定版本的bin目錄下,就可以使用該版本的jshell了.
image.png
簡單的輸出語句
image.png
變量定義:
image.png
方法定義和調用
image.png
導包處理
image.png
??其實jshell中有默認的導入一些包(除了java.lang之外,以下包也可以直接用),可以直接使用不用導包,查看有哪些:
image.png
常用命令
image.png
image.png
上面操作的代碼關閉窗口后就消失了。如果我們需要持久化相關的代碼,也可以操作
image.png
退出jshell
在開發Java程序之前,我們先要搞明白JDK、JRE以及JVM的區別
名稱 | 作用 |
JDK | 開發Java程序所需的工具包 |
JRE | 運行Java程序的環境 |
JVM | 包含在JVM內部,用于執行Java程序 |
三者的關系 JDK包含JRE,JRE包含JVM。作為開發者,我們只需要在電腦上安裝JDK就可以了。
Java早期是Sun公司的產品,后來被Oracle公司收購了。
點擊下邊鏈接
https://www.oracle.com/java/technologies/downloads/
進入到下載頁面,切換到window版本的JDK,并且選擇對應Installer進行下載
JDK下載頁面
a、雙擊運行安裝文件 jdk-xxx_windows-x64_bin.exe
b、指定jdk安裝目錄 C:\Java\jdk1.8.0_144 然后點擊“下一步”
jdk的安裝目錄設置
c、指定JRE安裝目錄 C:\Java\jre1.8.0_144,點擊“下一步”
安裝過程jre設置
d、安裝完成,點擊“關閉”即可
點擊鍵盤的windows鍵,輸入“編輯系統環境變量”,并打開
在系統屬性對話框,點擊高級→環境變量
a、新建 JAVA_HOME 環境變量,變量名為:JAVA_HOME,變量值為:C:\Java\jdk1.8.0_144(jdk的安裝目錄,根據自己的存放目錄填寫)
b、修改 path 環境變量,在path變量尾部添加%JAVA_HOME%\bin
c、新建 classpath 環境變量 ,變量名為:classpath,變量值為:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\tools.jar(注意變量值前面有.;)
說明:(jdk 需要配置三個環境變量; 1.5之后可以不再設置classpath,但建議保留classpath設置)
a、打開cmd命令窗口(鍵盤組合鍵window+r),輸入 java ,回車執行
b、輸入javac 命令,回車執行
顯示了java 和javac的版本信息說明jdk安裝配置成功
動動小手?關注我,與你分享更好的內容。