當前位置: 妍妍網 > 碼農

扛不住誘惑,我準備轉投 JDK17 了....

2024-06-28碼農

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