JDK16发布了!
JDK16已于北美時間3月16日發布,對Java開發者來說,JDK的這次更新總共帶來了12個全新的特性
1. 支持類型匹配的instanceof
if?(obj?instanceof?String)?{String?s?=?(String)?obj;????//?grr...... }這樣的類型轉換在JDK16中的寫法是:
if?(obj?instanceof?String?s)?{//?Let?pattern?matching?do?the?work!//?varialble?s?can?be?used?here... }如果obj的真實類型是String,則變量s可以在if語句中使用,但是如果obj的類型不是String,則s不能用在后續的變量命名中:
//?a?is?not?instance?of?Point if?(a?instanceof?Point?p)?{... } if?(b?instanceof?Point?p)?{?????????//?ERROR?-?p?is?in?scope... }2. record關鍵字
對于一些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關鍵字之后,上面的代碼可以簡化為:
record?Point(int?x,?int?y)?{?}如果對類的屬性初始化的時候有定制邏輯,也是支持的
record?Rational(int?num,?int?denom)?{Rational?{int?gcd?=?gcd(num,?denom);num?/=?gcd;denom?/=?gcd;} }3.全并發的ZGC
與CMS中的ParNew和G1類似,ZGC也采用標記-復制算法,不過ZGC對該算法做了重大改進:ZGC在標記、轉移和重定位階段幾乎都是并發的,這是ZGC實現停頓時間小于10ms目標的最關鍵原因。
ZGC只有三個STW階段:初始標記,再標記,初始轉移。其中,初始標記和初始轉移分別都只需要掃描所有GC Roots,其處理時間和GC Roots的數量成正比,一般情況耗時非常短;再標記階段STW時間很短,最多1ms,超過1ms則再次進入并發標記階段。即,ZGC幾乎所有暫停都只依賴于GC Roots集合大小,停頓時間不會隨著堆的大小或者活躍對象的大小而增加。與ZGC對比,G1的轉移階段完全STW的,且停頓時間隨存活對象的大小增加而增加。
4. 可彈性伸縮的元數據區
JDK16對元數據區切分為更小的內存塊,并將不再使用的內存快速返還給操作系統,對于頻繁加載和卸載類的應用來說這一優化可以產生大量的空閑內存,提升整個JVM的性能
5. 支持Unix套接字
在2019 Windows Server和Windows 10提供了對Unix套接字的支持,Unix套接字常用于本地進程之間通信,相比于TCP協議,本地進程使用Unix套接字可以更高效安全的通信。JDK16新增了一個適配Unix套接字的新接口java.net.UnixDomainSocketAddress用于支持這一特性
6. 新的打包工具jpackage
支持將Java程序打包為對應平臺的可執行程序
linux: deb和rpm
mac: pkg和dmg
Windows: msi和exe 假如我們在lib目錄下有一個jar包組成的應用,并且main.jar包含main方法,則可以使用下面的語句產生對應平臺的可執行程序
如果main.jar的MANIFEST.MF沒有指定main函數,則需要在命令行中指定
jpackage?--name?myapp?--input?lib?--main-jar?main.jar?\--main-class?myapp.Main7. 針對Value-Based類的編譯器warning提示
對于基本類型的包裝類,JDK16提供了兩種新的編譯器warning提示
包裝類的構造函數在JDK9已經被廢棄,如果在程序中繼續使用,則編譯器會報warning提示
如果包裝類作為關鍵字synchronized的參數使用,則也會收到編譯器的warning提示
如果接口類作為關鍵字synchronized的參數使用,則會收到javac編譯器的warning提示 舉例:
8. 對JDK內部方法提供強制的封裝
這個更新目的是為了引導開發者放棄使用JDK內部類轉為使標準的API接口,除了例如sun.misc.Unsafe這樣內部關鍵的接口之外,其他所有內部元素都提供默認的封裝。使用了JDK內部接口的代碼再JDK16下編譯會失敗,JVM參數-–illegal-access能夠控制這一行為,要知道從JDK9到JDK15,這個參數默認的值都是warning,而現在已經變成了deny
9. 提供向量計算的API
之前向量計算的API在JDK中是缺失的,常見的二方庫有colt和commons-math3,這些二方庫在版本老舊,在易用性上也比較差,此次JDK16引入的向量計算的API針對多數現代CPU使用的SIMD指令進行了優化,大幅提升了計算性能
10. 對原生代碼的調用提供更方便的支持
相比于JNI,提供更方便的方法用于調用原生代碼,比如我們想在Java代碼中調用size_t strlen(const char *s);這個原生C函數,我們只需要這樣寫:
MethodHandle?strlen?=?CLinker.getInstance().downcallHandle(LibraryLookup.ofDefault().lookup("strlen"),MethodType.methodType(long.class,?MemoryAddress.class),FunctionDescriptor.of(C_LONG,?C_POINTER));11. 提供操作外部內存的能力
JDK16通過VarHandle這個類的實例來引用外部內存區域,如果我們想初始化一段外部的內存區域,可以這樣寫:
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. 提供限制可以繼承此類的關鍵字sealed和permits
在JDK16中,提供了一種比訪問修飾符更精細的控制手段:可以指定可以繼承或者實現當前類或者接口的類,這個能力是通過關鍵字sealed和permits實現的
public?abstract?sealed?class?Shape?permits?com.example.polar.Circle,com.example.quad.Rectangle,com.example.quad.simple.Square?{?...?}比如在上面的這個例子中,類Shape只能限定被Circle,Rectangle和Square繼承
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
- 上一篇: EasyNVR支持的摄像机、NVR设备接
- 下一篇: nodejs 利用zip-local模块