👉 這是一個或許對你有用的社群
《專案實戰(影片)》:從書中學,往事上“練” 《網際網路高頻面試題》:面朝簡歷學習,春暖花開 《架構 x 系統設計》:摧枯拉朽,掌控面試高頻場景題 《精進 Java 學習指南》:系統學習,網際網路主流技術棧 《必讀 Java 原始碼專欄》:知其然,知其所以然

👉這是一個或許對你有用的開源專案國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、CRM 等等功能:
Boot 倉庫:https://gitee.com/zhijiantianya/ruoyi-vue-pro Cloud 倉庫:https://gitee.com/zhijiantianya/yudao-cloud 影片教程:https://doc.iocoder.cn 【國內首批】支援 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 雙版本

DK17語法新特性
文字塊
這個更新非常實用。在沒有這個特性之前,編寫長文字非常痛苦。雖然IDEA等整合開發工具可以自動處理,但最終效果仍然醜陋,充滿拼接符號。現在,透過字串塊,我們可以輕鬆編寫JSON、HTML、SQL等內容,效果更清爽。這個新特性值得五顆星評價,因為它讓我們只需關注字串本身,而無需關心拼接操作。
/**
* 使用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>
"
""
;
}
推薦指數:⭐️⭐️⭐️⭐️⭐️
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();
}
}

推薦指數:⭐️⭐️⭐️⭐️⭐️
Records
在Java中,POJO物件(如DO、PO、VO、DTO等)通常包含成員變數及相應的Getter和Setter方法。儘管可以透過工具或IDE生成這些程式碼,但修改和維護仍然麻煩。Lombok外掛為此出現,能夠在編譯期間自動生成Getter、Setter、hashcode、equals和建構函式等程式碼,使用起來方便,但對團隊有依賴要求。為此,Java引入了標準解決方案:Records。它透過簡潔的語法定義資料類,大大簡化了POJO類的編寫,如下所示。雖然hashcode和equals方法仍需手動編寫,但IDE能夠自動生成。這一特性有效解決了模板程式碼問題,提升了程式碼整潔度和可維護性。
package
com.xttblog.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
,
"男"
,
);
System.out.println(record);
}
}
推薦指數:⭐️⭐️⭐️⭐️
全新的switch表示式
有人可能問了,Java語言不早已支援switch了嘛,有什麼好提的?講真,這次的提升還真有必要好好地來聊一聊了。在Java12的時候就引入了switch表示式,注意這裡是表示式,而不是語句,原來的switch是語句。如果不清楚兩者的區別的話,最好先去了解一下。主要的差別就是就是表示式有返回值,而語句則沒有。再配合模式匹配,以及yield和“->”符號的加入,全新的switch用起來爽到飛起來。
package
com.xttblog.jdk17;
publicclassSwitchDemo
{
/**
* 在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
}
}
推薦指數:⭐️⭐️⭐️⭐️
私有介面方法
從Java8開始,允許在interface裡面新增預設方法,其實當時就有些小困惑,如果一個default方法體很大怎麼辦,拆到另外的類去寫嗎?實在有些不太合理,所以在Java17裡面,如果一個default方法體很大,那麼可以透過新增介面私有方法來進行一個合理的拆分了,為這個小改進點個贊。
publicinterfacePrivateInterfaceMethod
{
/**
* 介面預設方法
*/
defaultvoiddefaultMethod()
{
privateMethod();
}
// 介面私有方法,在Java8裡面是不被允許的,不信你試試
privatevoidprivateMethod()
{
}
}
推薦指數:⭐️⭐️⭐️
模式匹配
在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());
}
}
推薦指數:⭐️⭐️⭐️⭐️
集合類的工廠方法
在Java8的年代,即便建立一個很小的集合,或者固定元素的集合都是比較麻煩的,為了簡潔一些,有時我甚至會引入一些依賴。
Set<String> set =
new
HashSet<>();
set.add(
"a"
);
set.add(
"b"
);
set.add(
"c"
Set<String> set = Set.of(
"a"
,
"b"
,
"c"
);
推薦指數:⭐️⭐️⭐️⭐️⭐️
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/ruoyi-vue-pro 影片教程:https://doc.iocoder.cn/video/
其他的新特性
新的String方法
-
repeat:重複生成字串 -
isBlank:不用在引入第三方庫就可以實現字串判空了 -
strip:去除字串兩邊的空格,支援全形和半形,之前的trim只支援半形 -
lines:能根據一段字串中的終止符提取出行為單位的流 -
indent:給字串做縮排,接受一個int型的輸入 -
transform:接受一個轉換函式,實現字串的轉換
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));
全新的HttpClient
這個API首次出現在9之中,不過當時並非是一個穩定版本,在Java11中正式得到釋出,所以在Java17裡面可以放心地進行使用。原來的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);
jshell
在新的JDK版本中,支援直接在命令列下執行java程式,類似於python的互動式REPL。簡而言之,使用 JShell,你可以輸入程式碼片段並馬上看到執行結果,然後就可以根據需要作出調整,這樣在驗證一些簡單的程式碼的時候,就可以透過jshell得到快速地驗證,非常方便。
java命令直接執行java檔案
在現在可以直接透過執行“java xxx.java”,即可執行該java檔案,無須先執行javac,然後再執行java,是不是又簡單了一步。
ZGC
在ParallelOldGC、CMS和G1之後,JDK 11引入了全新的ZGC(Z Garbage Collector)。這個名字本身就顯得很牛。官方宣稱ZGC的垃圾回收停頓時間不超過10ms,能支援高達16TB的堆空間,並且停頓時間不會隨著堆的增大而增加。那麼,ZGC到底解決了什麼問題?Oracle官方介紹它是一個可伸縮的低延遲垃圾回收器,旨在降低停頓時間,儘管這可能會導致吞吐量的降低。不過,透過橫向擴充套件伺服器可以解決吞吐量問題。官方已建議ZGC可用於生產環境,這無疑將成為未來的主流垃圾回收器。要了解更多,請參閱官方文件https://docs.oracle.com/en/java/javase/17/gctuning/z-garbage-collector.html#GUID-9957D441-A99A-4CF5-9522-393E6DE7D898
。
小結一下





