哈囉大家好,這裡是對於Java的更新越來越滿意的小編過路君子
小編一路從 Java 11→ Java 17→ Java 21 用到現在最新的 Java 25,真的感覺越來越現代了!
Project Valhalla 的口號是:
"Codes like a class, works like an int."
因為該計畫目前還在逐步執行當中,其中有非常多的詞目前都尚未有翻譯,這部分小編都會保持
所謂的 Project Valhalla 若全部達成,將直接消除 Java 中的基本型態(例如 int、long......等等)與 物件類型(例如 Integer、String......等等)之間長久以來的隔閡與效能落差。
這邊小編直接引用 Java 官方對於該計畫的介紹:
combining the abstractions of object-oriented programming
with the performance characteristics of simple primitives.
翻譯成中文如下:
將物件導向程式設計的抽象特性
和簡單基本型態的高效能特性結合在一起。
在 Project Valhalla 中,目前總共有兩大部分,分別是:
- JEP 401: Value Classes and Objects (項目核心)
- JEP 402: Classes for the Basic Primitives
整個 Project Valhalla 最大的終極目標就是要達成 Java 中的泛型特化(Universal Generics),簡單來說就是要將 int 之類的基本型態變成一種 Value Class,讓 int 也具有相對應的方法,破除長期以來在 Java 中 int 和 Integer 之間的隔閡,致力於讓未來的 Java 能宣告 List<int> 這樣的變數。
其中的 JEP 401 目前有部分功能已經在 Java 25 中以預覽狀態呈現,同時引入新的關鍵字:value。
但小編認為之後如果這個功能實裝之後,這個 value 的關鍵字應該會被改掉,因為太!常!見!了!
一個大型的程式碼內小編就不相信沒有一堆叫做 value 的變數,都要全部改掉太搞人了,Java 的開發團隊應該沒有如此的不食人間煙火吧;總之,先來看看一個 value class 如何宣告吧:
public value class Point
{
int x;
final int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public double distance(Point other)
{
int dx = this.x - other.x;
int dy = this.y - other.y;
return Math.sqrt(dx * dx + dy * dy);
}
@Override
public String toString()
{
return "Point(" + x + ", " + y + ")";
}
}
在 value class 內部定義的變數都默認是 final 的,也就是說不管是沒有宣告 final 的 x 或是宣告了 final 的 y,皆是不可變動的。
同時,不僅僅像一般的類別一樣可以宣告函數,甚至還有預設函數可以複寫( toString、equals 或是 hashCode......等等函數 )。
當然,value class 也允許在宣告的時候包含其他的 value class:
public value class Rectangle
{
Point topLeft;
Point bottomRight;
public Rectangle(Point topLeft, Point bottomRight)
{
this.topLeft = topLeft;
this.bottomRight = bottomRight;
}
public int getArea()
{
int width = Math.abs(bottomRight.x - topLeft.x);
int height = Math.abs(bottomRight.y - topLeft.y);
return width * height;
}
}
在傳統的 class 中,topLeft 和 bottomRight 會記錄一個 reference,也就是我們常說的 call by reference;但是!在一個 value class 內,這兩個變數卻是以一個 value 的型態直接存儲在這個 value class 內,也就是說這個類別就像是 int 一樣變成了 call by value。
CPU 不再需要在記憶體內尋找散佈在各處的資料,而只需要增加特定的偏移量就可以讀取到資料了,以下:
傳統的 class 儲存另一個 class 方式:
[Rectangle 物件表頭]
+---> [指標 p1: 0x11] ---> (跳轉) ---> [Point 物件表頭 | x=10 | y=20]
+---> [指標 p2: 0x99] ---> (跳轉) ---> [Point 物件表頭 | x=30 | y=40]
新的 value class 儲存另一個 value class 方式:
[Rectangle 物件表頭 | 10 | 20 | 30 | 40 ]
↑ ↑ ↑ ↑
(p1.x p1.y p2.x p2.y)
接下來就可以執行測試了:
public class Main
{
public static void main(String[] args)
{
Point p1 = new Point(10, 20);
Point p2 = new Point(10, 20);
// Print: true
System.out.println((p1 == p2));
Rectangle rect = new Rectangle(p1, new Point(30, 40));
// Print: 400
System.out.println("矩形面積: " + rect.getArea());
// Print: Point(10, 20)
System.out.println(p1);
}
}
除了上面提到的之外,還有一個前置計畫在 Java 25 中已經轉為正式功能,也就是 JEP 482/492 Flexible Constructor Bodies。
簡單來說,在 Java 25 中 super() 並不再被規定必須放在建構子的第一行,此 JEP 允許我們在 super() 前面撰寫程式碼。
在 Java 25 之前的年代,如果我們要在 super() 之前執行程式碼,就只能使用 「靜態方法繞路法」 來繞過這個限制。
假設我們現在有一父類別 Person:
public class Person
{
public Person(String name, UUID id)
{
if (name == null || id == null) throw new IllegalArgumentException("data error");
System.out.println("Person construct done: " + name);
}
}
在 JEP 482/492 更新之前,也就是 Java 24 及以前的 Java 版本,我們只能透過靜態函數繞過 super() 限制:
public class Employee extends Person
{
private static UUID prepareUUID(String idStr)
{
if (idStr == null) throw new IllegalArgumentException("Request ID.");
try {return UUID.fromString(idStr);}
catch (IllegalArgumentException e) {throw new IllegalArgumentException("Unsupport UUID");}
}
public Employee(String name, String idStr)
{
super(name, prepareUUID(idStr));
System.out.println("Done!");
}
}
這樣不僅僅會造成邏輯紊亂,也會造成程式碼上的不直觀,我們必須在閱讀建構子的時候將視線往上往下不斷的跳動,而且也僅僅為了一個簡單的變數檢查或轉換宣告一個靜態變數,未免有點殺雞焉用牛刀。
而目前最新的 Java 25 則改善了這樣的狀態,super() 並不再被要求必須寫在建構子的第一行:
public class Employee extends Person
{
public Employee(String name, String idStr)
{
if (idStr == null) throw new IllegalArgumentException("Request ID.");
UUID uuid;
try {uuid = UUID.fromString(idStr);}
catch (IllegalArgumentException error) {throw new IllegalArgumentException("Unsupport UUID");}
// NOTICE HERE!
super(name, uuid);
System.out.println("Done!");
}
}
但是這並不是毫無限制的,Java 為了維持 Java 的安全性,在 super() 執行前,程式碼呈現「半靜態」的狀態,所以一切跟 this 有關的呼叫都被禁止。
但這不包括該類型的靜態成員,靜態成員依舊可以進行呼叫,因為靜態成員並不依賴 this 作為記憶體位置判斷。
直到執行完 super() 之後才能正常的呼叫 this,在這之前,僅能執行做任何不依賴 this 的程式碼。
以上,就是小編 Project Valhalla 的介紹啦,當然不僅僅只有這些更新,只是小編覺得其中的這個更新非常的棒,迫不及待的想和各位分享。
最後這些畢竟還只是預覽功能,未來可能會有更新或是修正,但小編還是希望 value class 這個預覽功能能成功轉為正式功能,這樣就可以宣告類似 List<int> 這樣的類別了,不用再使用彆腳的 List<Integer> 了。
後記
除了這個預覽功能外,Java 25 還新增了 import module 這個功能,可以把大量的 import 縮寫成一行。
不同於使用星號(*),import module 可以一次 import 不同路徑下的類別,甚至可以 import 第三方的函式庫!
以後有機會小編再來詳細展開來說說。
