JKD16發(fā)布,12個(gè)新特性一覽!
2、分庫(kù)分表?如何做到永不遷移數(shù)據(jù)和避免熱點(diǎn)?
3、36 張圖梳理 Intellij IDEA 常用設(shè)置,寫代碼賊爽!
JDK16已于北美時(shí)間3月16日發(fā)布,對(duì)Java開發(fā)者來(lái)說(shuō),JDK的這次更新總共帶來(lái)了12個(gè)全新的特性
1. 支持類型匹配的instanceof
if (obj instanceof String) {
String s = (String) obj; // grr...
...
}
這樣的類型轉(zhuǎn)換在JDK16中的寫法是:
if (obj instanceof String s) {
// Let pattern matching do the work!
// varialble s can be used here
...
}
如果obj的真實(shí)類型是String,則變量s可以在if語(yǔ)句中使用,但是如果obj的類型不是String,則s不能用在后續(xù)的變量命名中:
// a is not instance of Point
if (a instanceof Point p) {
...
}
if (b instanceof Point p) { // ERROR - p is in scope
...
}
2. record關(guān)鍵字
對(duì)于一些POJO類,我們往往需要這樣寫
class Point {
private final int x;
private final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
int x() { return x; }
int y() { return y; }
public boolean equals(Object o) {
if (!(o instanceof Point)) return false;
Point other = (Point) o;
return other.x == x && other.y == y;
}
public int hashCode() {
return Objects.hash(x, y);
}
public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
在引入了record關(guān)鍵字之后,上面的代碼可以簡(jiǎn)化為:
record Point(int x, int y) { }
如果對(duì)類的屬性初始化的時(shí)候有定制邏輯,也是支持的
record Rational(int num, int denom) {
Rational {
int gcd = gcd(num, denom);
num /= gcd;
denom /= gcd;
}
}
3.全并發(fā)的ZGC
與CMS中的ParNew和G1類似,ZGC也采用標(biāo)記-復(fù)制算法,不過(guò)ZGC對(duì)該算法做了重大改進(jìn):ZGC在標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,這是ZGC實(shí)現(xiàn)停頓時(shí)間小于10ms目標(biāo)的最關(guān)鍵原因。

ZGC只有三個(gè)STW階段:初始標(biāo)記,再標(biāo)記,初始轉(zhuǎn)移。其中,初始標(biāo)記和初始轉(zhuǎn)移分別都只需要掃描所有GC Roots,其處理時(shí)間和GC Roots的數(shù)量成正比,一般情況耗時(shí)非常短;再標(biāo)記階段STW時(shí)間很短,最多1ms,超過(guò)1ms則再次進(jìn)入并發(fā)標(biāo)記階段。即,ZGC幾乎所有暫停都只依賴于GC Roots集合大小,停頓時(shí)間不會(huì)隨著堆的大小或者活躍對(duì)象的大小而增加。與ZGC對(duì)比,G1的轉(zhuǎn)移階段完全STW的,且停頓時(shí)間隨存活對(duì)象的大小增加而增加。
4. 可彈性伸縮的元數(shù)據(jù)區(qū)
JDK16對(duì)元數(shù)據(jù)區(qū)切分為更小的內(nèi)存塊,并將不再使用的內(nèi)存快速返還給操作系統(tǒng),對(duì)于頻繁加載和卸載類的應(yīng)用來(lái)說(shuō)這一優(yōu)化可以產(chǎn)生大量的空閑內(nèi)存,提升整個(gè)JVM的性能
5. 支持Unix套接字
在2019 Windows Server和Windows 10提供了對(duì)Unix套接字的支持,Unix套接字常用于本地進(jìn)程之間通信,相比于TCP協(xié)議,本地進(jìn)程使用Unix套接字可以更高效安全的通信。JDK16新增了一個(gè)適配Unix套接字的新接口java.net.UnixDomainSocketAddress用于支持這一特性
6. 新的打包工具jpackage
支持將Java程序打包為對(duì)應(yīng)平臺(tái)的可執(zhí)行程序
linux: deb和rpm mac: pkg和dmg Windows: msi和exe 假如我們?cè)趌ib目錄下有一個(gè)jar包組成的應(yīng)用,并且 main.jar包含main方法,則可以使用下面的語(yǔ)句產(chǎn)生對(duì)應(yīng)平臺(tái)的可執(zhí)行程序
jpackage --name myapp --input lib --main-jar main.jar
如果main.jar的MANIFEST.MF沒(méi)有指定main函數(shù),則需要在命令行中指定
jpackage --name myapp --input lib --main-jar main.jar \
--main-class myapp.Main
7. 針對(duì)Value-Based類的編譯器warning提示
對(duì)于基本類型的包裝類,JDK16提供了兩種新的編譯器warning提示
包裝類的構(gòu)造函數(shù)在JDK9已經(jīng)被廢棄,如果在程序中繼續(xù)使用,則編譯器會(huì)報(bào) warning提示如果包裝類作為關(guān)鍵字 synchronized的參數(shù)使用,則也會(huì)收到編譯器的warning提示如果接口類作為關(guān)鍵字 synchronized的參數(shù)使用,則會(huì)收到javac編譯器的warning提示 舉例:
Double d = 20.0;
synchronized (d) { ... } // javac warning & HotSpot warning
Object o = d;
synchronized (o) { ... } // HotSpot warning
8. 對(duì)JDK內(nèi)部方法提供強(qiáng)制的封裝
這個(gè)更新目的是為了引導(dǎo)開發(fā)者放棄使用JDK內(nèi)部類轉(zhuǎn)為使標(biāo)準(zhǔn)的API接口,除了例如sun.misc.Unsafe這樣內(nèi)部關(guān)鍵的接口之外,其他所有內(nèi)部元素都提供默認(rèn)的封裝。使用了JDK內(nèi)部接口的代碼再JDK16下編譯會(huì)失敗,JVM參數(shù)-–illegal-access能夠控制這一行為,要知道從JDK9到JDK15,這個(gè)參數(shù)默認(rèn)的值都是warning,而現(xiàn)在已經(jīng)變成了deny
9. 提供向量計(jì)算的API
之前向量計(jì)算的API在JDK中是缺失的,常見(jiàn)的二方庫(kù)有colt和commons-math3,這些二方庫(kù)在版本老舊,在易用性上也比較差,此次JDK16引入的向量計(jì)算的API針對(duì)多數(shù)現(xiàn)代CPU使用的SIMD指令進(jìn)行了優(yōu)化,大幅提升了計(jì)算性能
10. 對(duì)原生代碼的調(diào)用提供更方便的支持
相比于JNI,提供更方便的方法用于調(diào)用原生代碼,比如我們想在Java代碼中調(diào)用size_t strlen(const char *s);這個(gè)原生C函數(shù),我們只需要這樣寫:
MethodHandle strlen = CLinker.getInstance().downcallHandle(
LibraryLookup.ofDefault().lookup("strlen"),
MethodType.methodType(long.class, MemoryAddress.class),
FunctionDescriptor.of(C_LONG, C_POINTER)
);
11. 提供操作外部?jī)?nèi)存的能力
JDK16通過(guò)VarHandle這個(gè)類的實(shí)例來(lái)引用外部?jī)?nèi)存區(qū)域,如果我們想初始化一段外部的內(nèi)存區(qū)域,可以這樣寫:
VarHandle intHandle = MemoryHandles.varHandle(int.class,
ByteOrder.nativeOrder());
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
for (int i = 0; i < 25; i++) {
intHandle.set(segment, i * 4, i);
}
}
12. 提供限制可以繼承此類的關(guān)鍵字sealed和permits
在JDK16中,提供了一種比訪問(wèn)修飾符更精細(xì)的控制手段:可以指定可以繼承或者實(shí)現(xiàn)當(dāng)前類或者接口的類,這個(gè)能力是通過(guò)關(guān)鍵字sealed和permits實(shí)現(xiàn)的
public abstract sealed class Shape
permits com.example.polar.Circle,
com.example.quad.Rectangle,
com.example.quad.simple.Square { ... }
比如在上面的這個(gè)例子中,類Shape只能限定被Circle,Rectangle和Square繼承
往期熱門文章:
1、《歷史文章分類導(dǎo)讀列表!精選優(yōu)秀博文都在這里了!》
2、阿里一面:如何保障消息100%投遞成功、消息冪等性? 3、GitHub 熱榜:被網(wǎng)友瘋狂惡搞的「螞蟻呀嘿」項(xiàng)目終于開源了! 4、記?。】葱‰娪扒耙欢ㄒ獧z查一下域名是不是 HTTPS 的,不然.... 5、拿到年終獎(jiǎng)后馬上辭職,厚道嗎? 6、Redis 內(nèi)存滿了怎么辦? 7、在 IDE 中玩轉(zhuǎn) GitHub 8、死磕18個(gè)Java8日期處理,工作必用! 9、把我坑慘的一個(gè)MySQL雙引號(hào)! 10、2021年 我辭職了!
