JDK17都出來了,你還在用JDK8?
JDK17的一些新特性
本文旨在介紹一些JDK17的新特性,同時限于篇幅,本文僅列舉其中一些差異,而不是全部差異;
PS: JDK17是Java的一個LTS版本(長期支持版本),可以放心遷移過來;
instanceof
JDK8中的語法:
Object o = something;
if (o instanceof String) {
String str = (String)o;
// do something
}
在JDK17中我們可以這樣寫:
Object o = something;
if (o instanceof String str) {
// do something, 注意上邊String后邊跟了一個str,相當(dāng)于把o強轉(zhuǎn)為String同時使用變量名str引用,我們后續(xù)可以直接使用str而不用再加一層強轉(zhuǎn)了
}
switch
普通switch
如果switch中只有一條語句時,JDK8中的語法:
String str = something;
switch (str) {
case "123":
System.out.println(str);
break;
case "456":
System.out.println(str);
break;
}
可以看出每個case后邊都需要一個?break?,否則會穿透到后邊的?case?語句;
JDK17中的語法:
String str = something;
switch (str) {
case "123" -> System.out.println(str);
case "456" -> System.out.println(str);
default -> System.out.println(str);
}
switch的模式匹配
JDK8中的語法:
Object o = something;
if (o instanceof String) {
String str = (String)o;
// do something
} else if (o instanceof Integer) {
Integer integer = (Integer)o;
// do something
}
在JDK17中我們可以這樣寫(case語句也可以展開,這里為了省事就用了這種寫法):
Object o = something;
switch (o) {
case Integer i -> System.out.println(i);
case String str -> System.out.println(str);
default -> System.out.println(o);
}
null值處理
傳統(tǒng)(JDK8)switch語句需要提前判null,否則會拋出NPE:
String str = something;
if (str == null) {
// do something
return;
}
switch (str) {
case "123":
System.out.println(str);
break;
case "456":
System.out.println(str);
break;
}
JDK17中無需判空,可以直接?case null?:
String str = something;
switch (str) {
case null -> System.out.println("null");
case "123" -> System.out.println(str);
case "456" -> System.out.println(str);
default -> System.out.println(str);
}
復(fù)雜條件的case優(yōu)化:
對于以下代碼:
class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }
static void testTriangle(Shape s) {
switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {
System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}
可以優(yōu)化為:
class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) ->
System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}
密封類(sealed Class)
在JDK8中,如果我們一個類只想要只想要指定的子類(我們自己編寫的類)實現(xiàn),而不希望其他依賴方自己實現(xiàn)(這種場景在框架編寫中很常見),我們通常的方法是將構(gòu)造器設(shè)置為私有的,然后使用 靜態(tài)內(nèi)部類來繼承該類,或者將構(gòu)造器設(shè)置為package訪問級別的,然后在同一個包中編寫類來繼承;這兩種方式雖然都能實現(xiàn)我們的目標(biāo)(在某些場景也能被打破,例如用戶自己編寫了一個同名包,然 后就能在包中繼續(xù)繼承該類了),但是都不是太優(yōu)雅,在我們升級JDK17后該問題也將被解決,JDK17中引入了一個新的關(guān)鍵字?sealed?用來修飾我們不想要其他人私自繼承的類(或者接口),然后使用?permits?關(guān)鍵字指定都有那些類可以繼承本類,用法如下:
public abstract sealed class TestA permits TestB {
}
public class TestB extends TestA {
}
這里我們使用?sealed?關(guān)鍵字聲明?TestA?不能隨便被其他類繼承,然后使用?permits?聲明只有?TestB?才能繼承?TestA?,注意,這里?TestB?和?TestA?必須在同一個包中,如 果不在同一個包中,那么?permits?關(guān)鍵字后的?TestB?必須帶包名(例如com.JoeKerouac.TestB);
聯(lián)系我
作者微信:JoeKerouac
微信公眾號(文章會第一時間更新到公眾號):代碼深度研究院
GitHub:https://github.com/JoeKerouac
參考文獻
jdk17完整發(fā)布變更說明文檔(注:截止文章發(fā)布時該地址仍有效,后續(xù)JDK繼續(xù)升級,JDK17被歸檔后該地址可能無效):https://jdk.java.net/17/release-notes
