雖然好像慢了,但還是小小來記錄一下java 16到底有什麼具體的改變,方便我跟版本,畢竟9月就要發布java 17(LTS,長期穩定支援版本)了,總不能一直抱著祖傳java 8。
我就挑我覺得比較酷的來說,因為網路上的內容基本上都講得滿模糊的,所以乾脆直接看oracle的java document,再加入我自己的一點理解。
Record Classes
Record Classes的官方預設用途是被拿來實作簡單的"數據載體"的,基本上就是一個我覺得還算好用的語法糖。
具體功能大概是這樣。
record Rectangle (double length, double width) { }
開發者寫的這一段code等效於以下的程式碼。
public final class Rectangle { private final double length; private final double width; public Rectangle (double length, double width) { this .length = length; this .width = width; } double length () { return this .length; } double width () { return this .width; } public boolean equals... public int hashCode... public String toString () {...} }
可以從上面看到輸入的數據會被寫死在class創建的時候 ,並且自動生成equals,hashCode和toString function,我覺得不算驚艷,但還不錯,可以快速的來處理簡單得數據資料。
來講一下equals()跟hashCode()的用途,在java當中,==運算子比較的是物件實體或者說是記憶體位置是否相同,而equals()可以比較物件的值是否相同。
hashCode()則是會回傳一個將過hash函數處裡的int值,可以被用來做HashMap、HashSet等雜湊資料結構的索引,讓使用者可以以hashCode()快速實現相關結構。
另外不能宣告instance variables(non-static fields)或者是instance initializers。
record Rectangle (double length, double width) { BiFunction<Double, Double, Double> diagonal; { diagonal = (x, y) -> Math.sqrt(x*x + y*y); } }
類似這樣的code將不會被編譯。
但可以在Record Classes當中聲明instance methods,像是以下程式碼。
record Rectangle (double length, double width) { record RotationAngle (double angle) { public RotationAngle { angle = Math.toRadians(angle); } } public Rectangle getRotatedRectangleBoundingBox (double angle) { RotationAngle ra = new RotationAngle (angle); double x = Math.abs(length * Math.cos(ra.angle())) + Math.abs(width * Math.sin(ra.angle())); double y = Math.abs(length * Math.sin(ra.angle())) + Math.abs(width * Math.cos(ra.angle())); return new Rectangle (x, y); } }
Pattern Matching for instanceof
instanceof是java當中的保留關鍵字,用於確認變數型態,當相同時就返回true,不同就返回false。
Double d = 0 ;if (d instanceof Double){ } if (d instanceof Boolean){ }
大概就會像是這個樣子,可以降低程式的bug還有一些implements的子class分類會很好弄,像是以下這樣。
public interface Shape { public static double getPerimeter (Shape shape) throws IllegalArgumentException { if (shape instanceof Rectangle) { Rectangle r = (Rectangle) shape; return 2 * r.length() + 2 * r.width(); } else if (shape instanceof Circle) { Circle c = (Circle) shape; return 2 * c.radius() * Math.PI; } else { throw new IllegalArgumentException ("Unrecognized shape" ); } } } public class Rectangle implements Shape { final double length; final double width; public Rectangle (double length, double width) { this .length = length; this .width = width; } double length () { return length; } double width () { return width; } } public class Circle implements Shape { final double radius; public Circle (double radius) { this .radius = radius; } double radius () { return radius; } }
而在java 16當中,有新的語法糖來簡化這個過程。
public static double getPerimeter (Shape shape) throws IllegalArgumentException { if (shape instanceof Rectangle r) { return 2 * r.length() + 2 * r.width(); } else if (shape instanceof Circle c) { return 2 * c.radius() * Math.PI; } else { throw new IllegalArgumentExceptio ("Unrecognized shape" ); } }
大概就是可以宣告一個變數並等同於shape以便後續使用。
Switch Expressions
Switch Expressions應該是我最喜歡的部分,他把switch弄得酷酷的。
public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; } int numLetters = 0 ; Day day = Day.WEDNESDAY; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: numLetters = 6 ; break ; case TUESDAY: numLetters = 7 ; break ; case THURSDAY: case SATURDAY: numLetters = 8 ; break ; case WEDNESDAY: numLetters = 9 ; break ; default : throw new IllegalStateException ("Invalid day: " + day); } System.out.println(numLetters);
在java 16中把這種又長又冗的寫法改為以下這種,有夠香的啦!我前陣子寫計算機概論的作業的時候用的滿開心的。
Day day = Day.WEDNESDAY; System.out.println( switch (day) { case MONDAY, FRIDAY, SUNDAY -> 6 ; case TUESDAY -> 7 ; case THURSDAY, SATURDAY -> 8 ; case WEDNESDAY -> 9 ; default -> throw new IllegalStateException ("Invalid day: " + day); } );
而如果要寫更多(不只一行)操作的話,可以用{}把內容括號起來執行,例如以下。
int numLetters = switch (day) { case MONDAY, FRIDAY, SUNDAY -> { System.out.println(6 ); yield 6 ; } case TUESDAY -> { System.out.println(7 ); yield 7 ; } case THURSDAY, SATURDAY -> { System.out.println(8 ); yield 8 ; } case WEDNESDAY -> { System.out.println(9 ); yield 9 ; } default -> { throw new IllegalStateException ("Invalid day: " + day); } };
封裝與其他部分
因為涉及到程式編寫層面較少,所以我把我覺得比較重要的改變拉出來集合成一個分類。
完整功能
java 16封裝了除了關鍵的內部API以外的所有內部方法,JDK默認為拒絕所有的非必要訪問,除非使用–add-opens打開特定套件。
優化ZGC(java內部提供的垃圾記憶體回收機制),以多執行續處理,極大的降低延遲。
可以將未使用的HotSpot VM metaspace 記憶體更快速的回傳給操作系統。
正在開發的項目和preview功能
Vector API : 在CPU架構上對向量運算做出優化,提供更高的性能。
Foreign Linker API : 把原本用來呼叫其他程式語言的JNI取代掉,該API提供靜態類型的純Java訪問,感覺比應該不會比JNI難用(?),我快受夠JNI了。
Sealed Classes : 可以限制那些class or interfaces可以extend or implement Sealed Classes和可以限制use of a superclass,目前還在預覽階段,但感覺是想未來逐漸取代掉class。
JDK內部改變