Since the previous LTS, JDK 17, was released in 2021, there are quite lots of features added into the Java specification. In this year, the latest JDK 21 LTS version is released and brings us many formal functions to improve our daily works. This session will focus on the new features, including String Templates, Sequenced Collections, Record Patterns, Pattern Matching for switch, Unnamed features and Virtual Threads.
6. 2023 State of Java Ecosystem
• New Relic first published in March 2020
• 2023 state was published in April 2023
• Based on data gathered from millions of
applications providing performance data
• The data for this report was drawn entirely
from applications reporting to New Relic in
January 2023 and does not provide a global
picture of Java usage.
6
Source: https://newrelic.com/resources/report/2023-state-of-java-ecosystem
16. Pattern Matching for switch
String text = switch (obj) {
case null -> "NULL"; // null check
case String s -> "String: " + s;
case Integer i
when i < 10_000 -> "Small Int: " + i;
case Integer i -> "Big Int: " + i;
case Long l -> "Long: " + l;
case Number n -> "Number: " + n;
default -> "Object: " + obj;
}
16
1. 可以檢查 null
2. 可以用 when 來增加判斷式
(guarded pattern)
3. Java14 讓 switch 可以回
傳值並設定 text 變數內容
17. 注意!上下順序很重要!
String text = switch (obj) {
case null -> "NULL";
case String s -> "String: " + s;
case Number n -> "Number: " + n;
// Error: this case label is dominated
// by a preceding case label
case Integer i -> "Integer: " + i; // unreachable
case Long l -> "Long: " + l;
default -> "Object: " + obj;
}
17
到不了的地方叫遠方
18. 支配權 Dominance
• 父類別大於子類別 (例:Number > Integer)
• Unguarded pattern 大於 guarded pattern
(case Type > case Type when expr.)
• Guarded pattern when true 大於其他
pattern(guarded & unguarded)
• Pattern 大於常數(Integer i > 1, 2)
• Enum 類別大於常數(Color > Color.RED)
• when 不會進行過多的額外檢查
18
19. 建議撰寫原則
• 先寫 case null (純粹為了易讀性與維護性)
• 次寫 case 常數和列舉常數
• 再寫 guarded 的 case Type t when 判斷式
• 後寫 unguarded 的 case Type t
• 特別注意 Type 的子類別要放在父類別之前
• 最後寫 default 做收尾(若未窮舉的話)
19
20. 搭配 enum 一起用
enum Color { RED, GREEN, BLUE, YELLOW, PURPLE }
String text = switch (obj) {
case null -> "NULL";
case Color.BLUE -> "Color.BLUE"; // 短版本
case Color c
when c == Color.RED -> "Color.RED";// 與上式等價
case Color c -> "Color: others"; // 注意支配性
case int[] ia -> "Int array: " + ia; // 陣列也可以
default -> "Object: " + obj;
}
20
記得 enum、sealed 需要注
意是否要窮舉所有可能值!
22. class Point { // immutable
private final int x, y;
public Point(int x, int y) { this.x=x; this.y=y; }
public int x() { return x; }
public int y() { return y; }
public boolean equals(Object o) {
return o instanceof Point
&& ((Point) o).x == x
&& ((Point) o).y == y;
}
public int hashCode() { return Objects.hash(x, y); }
public String toString() {
return String.format("Point[x=%d, y=%d]", x, y);
}
}
回到 Java 上古時代(= Java 7)
22
23. Java16 record + Java17 sealed
23
record Point(int x, int y) {} // 上頁的程式碼濃縮成一行了
// 順便增加一些複雜度
sealed interface Shape
permits Circle, Rectangle, Triangle {
public static void check(Point p) {
if (p.x() <= 0)
throw new IllegalArgumentException("NG!");
}
}
record Circle(Point p, int r, Color c)
implements Shape {}
record Rectangle(Point p1, Point p2, Color c)
implements Shape {}
record Triangle(Point p1, Point p2, Point p3, Color c)
implements Shape {}
24. return switch (obj) {
case null -> "NULL";
case Point p -> "Point: " + p; // Pattern matching
case Circle(Point p, int r, Color c) // record pattern
-> "Circle: p:" + p;
case Rectangle(Point p1, Point p2, Color c)
-> "Rectangle: 1:" + p1 + ", 2:" + p2;
case Triangle(Point p1, Point p2, Point p3, Color c)
-> "Triangle: 1:" + p1 + ", 2:" + p2 + ", 3:" + p3;
default -> "Object: " + obj;
};
24
這樣一來就不需要使用
case Circle c -> c.p();
Record Pattern
25. record Pair<T>(T a, T b) {}
private Pair<Shape> o;
switch (o) {
// 要窮舉所有可能值
case Pair<Shape>(Circle c, Shape s) -> ...
case Pair<Shape>(Rectangle r, Circle c) -> ...
case Pair<Shape>(Rectangle r, Rectangle r) -> ...
case Pair<Shape>(Rectangle r, Triangle t) -> ...
case Pair<Shape>(Triangle t, Shape s) -> ...
// 或是用下列任一行收尾
case Pair<Shape>(var a, var b) -> ...
case Pair<Shape> x -> ...
default -> ...
}
25
要注意是否已窮舉
26. If record in if
// Java 16 ~ 20
if (o instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x + y);
}
// Java 21 Record pattern
if (o instanceof Point(int x, int y)) {
System.out.println(x + y);
}
26
27. 更複雜的 Record Pattern
if (o instanceof Circle(Point(int x, int y), int r, Color c)) {
System.out.println(x + y);
}
if (o instanceof Rectangle(Point(var x,var y), var p2, var c)) {
System.out.println(x); // 也可以使用 var
}
if (o instanceof Triangle(Point(int x1, int y1),
Point(var x2, var y2), Point p3, var c)) {
System.out.println(c);
}
27
程式碼能夠
簡化嗎?
28. Unnamed Patterns (Preview)
if (o instanceof Circle(Point(int x, int y), int _, Color _) {
System.out.println(x + y); // unnamed pattern variable
}
if (o instanceof Rectangle(Point(var x, _), _, _) {
System.out.println(x); // unnamed pattern (Type v)
}
if (o instanceof Triangle(_, _, _, var c) { // unnamed pattern
System.out.println(c);
}
if (o instanceof Point _) { // unnamed pattern variable
System.out.println("Point!");
}
28
程式碼複雜度降
低,可讀性增加!
29. Unnamed Variables (Preview)
var points = new ArrayList<Point>(List.of(p1, p2, p3, p4, p5));
for (Point _ : points) { // enhanced for loop
if (DEBUG) count++;
}
for (int i = 0, _ = init(); i < count; i++) { // for statement
try (var _ = getRes()) { // try-with-resources statement
Point p = points.getFirst();
Shape.check(p);
m.putAll(Arrays.stream(Color.values())
.map(c -> new Circle(p, i, c))
.collect(toMap(Function.identity(),
_ -> 1L)) //lambda
);
} catch (IllegalArgumentException _) { // exception
var _ = points.removeFirst(); // local variable
}
}
29
30. 這是禁止事項 🙅
• o instanceof _
• o instanceof _(int x, int y)
• o instanceof var _
• case _
• case var _
• case Type(_)
• void test(String x, int _) {}
• ...
30
32. 各自表述,沒有共識
First element Last element
List list.get(0) list.get(list.size() - 1)
Deque deque.getFirst() deque.getLast()
SortedSet set.first() set.last()
LinkedHashSet set.iterator().next() // missing
32
不同集合取得
首尾元素有不
同做法……
35. SequencedCollection
// new method
SequencedCollection<E> reversed();
// methods promoted from Deque
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
// add*(E) & remove*() are optional (unmodifiable)
// get*() & remove*() throw NoSuchElementEx if empty
35
50. Core Java Library
• JEP 431: Sequenced Collections
• JEP 442: Foreign Function & Memory API
(Third Preview)
• JEP 444: Virtual Threads
• JEP 446: Scoped Values (Preview)
• JEP 448: Vector API (Sixth Incubator)
• JEP 453: Structured Concurrency (Preview)
50
51. Java Language Specification
• JEP 430: String Templates (Preview)
• JEP 440: Record Patterns
• JEP 441: Pattern Matching for switch
• JEP 443: Unnamed Patterns and Variables
(Preview)
• JEP 445: Unnamed Classes and Instance
Main Methods (Preview)
51
52. HotSpot & Security
• JEP 439: Generational ZGC
• JEP 449: Deprecate the Windows 32-bit x86
Port for Removal
• JEP 451: Prepare to Disallow the Dynamic
Loading of Agents
• JEP 452: Key Encapsulation Mechanism API
• NOTE THAT JEP 404, Generational
Shenandoah (Experimental), originally
targeted for 21, was officially removed
52