JDK版本升級的非常快,現在已經到JDK20了。JDK版本雖多,但套用最廣泛的還得是JDK8,正所謂「他發任他發,我用Java8」。
其實我也不太想升級JDK版本,感覺投入高,收益小,不過有一次我看到了一些使用JDK17新語法寫的程式碼,讓我改變了對升級JDK的看法,因為這些新語法我確實想用!
廢話不多說,上程式碼!
一、JDK17語法新特性
1. 文本塊
這個更新非常實用。在沒有這個特性之前,編寫長文本非常痛苦。雖然IDEA等整合開發工具可以自動處理,但最終效果仍然醜陋,充滿拼接符號。現在,透過字串塊,我們可以輕松編寫JSON、HTML、SQL等內容,效果更清爽。
這個新特性值得五顆星評價,因為它讓我們只需關註字串本身,而無需關心拼接操作。
如果你近期準備面試跳槽,建議在ddkk.com線上刷題,涵蓋 一萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術面試題,還有市面上最全的技術五百套,精品系列教程,免費提供。
原來的寫法
/**
* 使用JDK8返回HTML文本
*
* @return 返回HTML文本
*/
publicstaticfinal String getHtmlJDK8(){
return"<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>";
}
新的寫法
/**
* 使用JDK17返回HTML文本
*
* @return 返回HTML文本
*/
publicstaticfinal String getHtmlJDK17(){
return"""
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
}
推薦指數:⭐️⭐️⭐️⭐️⭐️
2. NullPointerException增強
這一功能非常強大且實用,相信每位Java開發者都期待已久。空指標異常(NPE)一直是Java程式設計師的痛點,因為報錯資訊無法直觀地指出哪個物件為空,只丟擲一個NullPointerException和一堆堆疊資訊,定位問題耗時且麻煩。
尤其在遇到喜歡級聯呼叫的程式碼時,逐行排查更是令人頭疼。如果在測試環境中,可能還需透過遠端偵錯查明空物件,費時費力。為此,阿裏的編碼規範甚至不允許級聯呼叫,但這並不能徹底解決問題。Java17終於在這方面取得了突破,提供了更詳細的空指標異常資訊,幫助開發者迅速定位問題源頭。
publicstaticvoidmain(String[] args){
try {
//簡單的空指標
String str = null;
str.length();
} catch (Exception e) {
e.printStackTrace();
}
try {
//復雜一點的空指標
var arr = List.of(null);
String str = (String)arr.get(0);
str.length();
} catch (Exception e) {
e.printStackTrace();
}
}
執行結果
推薦指數:⭐️⭐️⭐️⭐️⭐️
3. Records
在Java中,POJO物件(如DO、PO、VO、DTO等)通常包含成員變量及相應的Getter和Setter方法。盡管可以透過工具或IDE生成這些程式碼,但修改和維護仍然麻煩。Lombok外掛程式為此出現,能夠在編譯期間自動生成Getter、Setter、hashcode、equals和建構函式等程式碼,使用起來方便,但對團隊有依賴要求。
如果你近期準備面試跳槽,建議在ddkk.com線上刷題,涵蓋 一萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術面試題,還有市面上最全的技術五百套,精品系列教程,免費提供。
為此,Java引入了標準解決方案:Records。它透過簡潔的語法定義數據類,大大簡化了POJO類的編寫,如下所示。雖然hashcode和equals方法仍需手動編寫,但IDE能夠自動生成。這一特性有效解決了樣版程式碼問題,提升了程式碼整潔度和可維護性。
package com.summo.jdk17;
/**
* 3星
*
* @param stuId 學生ID
* @param stuName 學生名稱
* @param stuAge 學生年齡
* @param stuGender 學生性別
* @param stuEmail 學生信箱
*/
public record StudentRecord(Long stuId,
String stuName,
int stuAge,
String stuGender,
String stuEmail){
public StudentRecord {
System.out.println("建構函式");
}
publicstaticvoidmain(String[] args){
StudentRecord record = new StudentRecord(1L, "張三", 16, "男", "[email protected]");
System.out.println(record);
}
}
推薦指數:⭐️⭐️⭐️⭐️
4. 全新的switch運算式
有人可能問了,Java語言不早已支持switch了嘛,有什麽好提的?講真,這次的提升還真有必要好好地來聊一聊了。
在Java12的時候就引入了switch運算式,註意這裏是運算式,而不是語句,原來的switch是語句。如果不清楚兩者的區別的話,最好先去了解一下。主要的差別就是就是運算式有返回值,而語句則沒有。再配合模式匹配,以及yield和「->」符號的加入,全新的switch用起來爽到飛起來。
package com.summo.jdk17;
public classSwitchDemo{
/**
* 在JDK8中獲取switch返回值方式
*
* @param week
* @return
*/
publicintgetByJDK8(Week week){
int i = 0;
switch (week) {
case MONDAY, TUESDAY:
i = 1;
break;
case WEDNESDAY:
i = 3;
break;
case THURSDAY:
i = 4;
break;
case FRIDAY:
i = 5;
break;
case SATURDAY:
i = 6;
break;
case SUNDAY:
i = 7;
break;
default:
i = 0;
break;
}
return i;
}
/**
* 在JDK17中獲取switch返回值
*
* @param week
* @return
*/
publicintgetByJDK17(Week week){
// 1, 現在的switch變成了運算式,可以返回值了,而且支持yield和->符號來返回值
// 2, 再也不用擔心漏寫了break,而導致出問題了
// 3, case後面支持寫多個條件
returnswitch (week) {
casenull -> -1;
case MONDAY -> 1;
case TUESDAY -> 2;
case WEDNESDAY -> 3;
case THURSDAY -> {yield 4;}
case FRIDAY -> 5;
case SATURDAY, SUNDAY -> 6;
default -> 0;
};
}
privateenum Week {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
}
推薦指數:⭐️⭐️⭐️⭐️
5. 私有介面方法
從Java8開始,允許在interface裏面添加預設方法,其實當時就有些小困惑,如果一個default方法體很大怎麽辦,拆到另外的類去寫嗎?
實在有些不太合理,所以在Java17裏面,如果一個default方法體很大,那麽可以透過新增介面私有方法來進行一個合理的拆分了,為這個小改進點個贊。
publicinterfacePrivateInterfaceMethod{
/**
* 介面預設方法
*/
defaultvoiddefaultMethod(){
privateMethod();
}
// 介面私有方法,在Java8裏面是不被允許的,不信你試試
privatevoidprivateMethod(){
}
}
推薦指數:⭐️⭐️⭐️
6. 模式匹配
在JDK 17中,模式匹配主要用於instanceof運算式。模式匹配增強了instanceof的語法和功能,使型別檢查和型別轉換更加簡潔和高效。在傳統的Java版本中,我們通常使用instanceof結合型別轉換來判斷物件型別並進行處理,這往往會導致冗長的程式碼。
原來的寫法
/**
* 舊式寫法
*
* @param value
*/
publicvoidmatchByJDK8(Object value){
if (value instanceof String) {
String v = (String)value;
System.out.println("遇到一個String型別" + v.toUpperCase());
} elseif (value instanceof Integer) {
Integer v = (Integer)value;
System.out.println("遇到一個整型型別" + v.longValue());
}
}
新的寫法
/**
* 轉換並申請了一個新的變量,極大地方便了程式碼的編寫
*
* @param value
*/
publicvoidmatchByJDK17(Object value){
if (value instanceof String v) {
System.out.println("遇到一個String型別" + v.toUpperCase());
} elseif (value instanceof Integer v) {
System.out.println("遇到一個整型型別" + v.longValue());
}
}
推薦指數:⭐️⭐️⭐️⭐️
7. 集合類的工廠方法
在Java8的年代,即便建立一個很小的集合,或者固定元素的集合都是比較麻煩的,為了簡潔一些,有時我甚至會引入一些依賴。
原來的寫法
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c"
新的寫法
Set<String> set = Set.of("a", "b", "c");
推薦指數:⭐️⭐️⭐️⭐️⭐️
二、其他的新特性
1. 新的String方法
repeat
:重復生成字串
isBlank
:不用在引入第三方庫就可以實作字串判空了
strip
:去除字串兩邊的空格,支持全形和半形,之前的trim只支持半形
lines
:能根據一段字串中的終止符提取出行為單位的流
indent
:給字串做縮排,接受一個int型的輸入
transform
:接受一個轉換函式,實作字串的轉換
2. Stream API的增強
增加takeWhile, dropWhile, ofNullable, iterate以及toList的API,越來越像一些函式式語言了。用法舉例如下。
// takeWhile 順序返回符合條件的值,直到條件不符合時即終止繼續判斷,
// 此外toList方法的加入,也大大減少了節省了程式碼量,免去了呼叫collect(Collectors::toList)方法了
List<Integer> list = Stream.of(2,2,3,4,5,6,7,8,9,10)
.takeWhile(i->(i%2==0)).toList(); // 返回2, 2
// dropWhile 順序去掉符合條件的值,直到條件不符合時即終止繼續判斷
List<Integer> list1 = Stream.of(2,2,3,4,5,6,7,8,9,10)
.dropWhile(i->(i%2==0)).toList(); //返回3, 4, 5, 6, 7, 8, 9, 10
// ofNullable,支持傳入空流,若沒有這個且傳入一個空流,那麽將會拋NPE
var nullStreamCount = Stream.ofNullable(null).count(); //返回0
// 以下兩行都將輸出0到9
Stream.iterate(0, n -> n < 10, n -> n + 1).forEach(x -> System.out.println(x));
Stream.iterate(0, n -> n + 1).limit(10).forEach(x -> System.out.println(x));
3. 全新的HttpClient
這個API首次出現在9之中,不過當時並非是一個穩定版本,在Java11中正式得到釋出,所以在Java17裏面可以放心地進行使用。
如果你近期準備面試跳槽,建議在ddkk.com線上刷題,涵蓋 一萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術面試題,還有市面上最全的技術五百套,精品系列教程,免費提供。
原來的JDK內建的Http客戶端真的非常難用,這也就給了很多像okhttp、restTemplate、Apache的HttpClient和feign這樣的第三方庫極大的發揮空間,幾乎就沒有人願意去用原生的Http客戶端的。
但現在不一樣了,感覺像是新時代的API了。FluentAPI風格,處處充滿了現代風格,用起來也非常地方便,再也不用去依賴第三方的包了,就兩個字,清爽。
// 同步請求
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
.authenticator(Authenticator.getDefault())
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
// 異步請求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://foo.com/"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
4. jshell
在新的JDK版本中,支持直接在命令列下執行java程式,類似於python的互動式REPL。簡而言之,使用 JShell,你可以輸入程式碼片段並馬上看到執行結果,然後就可以根據需要作出調整,這樣在驗證一些簡單的程式碼的時候,就可以透過jshell得到快速地驗證,非常方便。
5. java命令直接執行java檔
在現在可以直接透過執行「
java xxx.java
」,即可執行該java檔,無須先執行javac,然後再執行java,是不是又簡單了一步。
6. ZGC
在ParallelOldGC、CMS和G1之後,JDK 11引入了全新的ZGC(Z Garbage Collector)。這個名字本身就顯得很牛。官方宣稱ZGC的垃圾回收停頓時間不超過10ms,能支持高達16TB的堆空間,並且停頓時間不會隨著堆的增大而增加。
如果你近期準備面試跳槽,建議在ddkk.com線上刷題,涵蓋 一萬+ 道 Java 面試題,幾乎覆蓋了所有主流技術面試題,還有市面上最全的技術五百套,精品系列教程,免費提供。
那麽,ZGC到底解決了什麽問題?Oracle官方介紹它是一個可伸縮的低延遲垃圾回收器,旨在降低停頓時間,盡管這可能會導致吞吐量的降低。不過,透過橫向擴充套件伺服器可以解決吞吐量問題。官方已建議ZGC可用於生產環境,這無疑將成為未來的主流垃圾回收器。要了解更多,請參閱官方文件:
❝
https://docs.oracle.com/en/java/javase/17/gctuning/z-garbage-collector.html
三、小結一下
作為程式設計師,持續學習和充電非常重要。隨著Java8即將停止免費官方支持,越來越多的計畫將轉向Java17,包括大名鼎鼎的Spring Boot 3.0,它在2022年1月20日釋出的第一個裏程碑版本(M1)正是基於Java17構建的。該計畫依賴的所有元件也將快速升級,未來如果想利用某些新特性,在Java8下將無法透過編譯.,到這時候再換就真的晚了... ...
來源:juejin.cn/post/7376444924424241162