Java 语言个性系列
- Java5 的新个性
- Java6 的新个性
- Java7 的新个性
- Java8 的新个性
- Java9 的新个性
- Java10 的新个性
- Java11 的新个性
- Java12 的新个性
- Java13 的新个性
- Java14 的新个性
- Java15 的新个性
- Java16 的新个性
- Java17 的新个性
- Java18 的新个性
- Java19 的新个性
- Java20 的新个性
- Java21 的新个性
序
本文次要讲述一下 Java20 的新个性
版本号
java -version
openjdk version "20" 2023-03-21
OpenJDK Runtime Environment (build 20+36-2344)
OpenJDK 64-Bit Server VM (build 20+36-2344, mixed mode, sharing)
从 version 信息能够看出是 build 20+36
个性列表
JEP 429: Scoped Values (Incubator)
ScopedValue 是一种相似 ThreadLocal 的线程内 / 父子线程传递变量的更优计划。ThreadLocal 提供了一种无需在办法参数上传递通用变量的办法,InheritableThreadLocal 使得子线程能够拷贝继承父线程的变量。然而 ThreadLocal 提供了 set 办法,变量是可变的,另外 remove 办法很容易被疏忽,导致在线程池场景下很容易造成内存泄露。ScopedValue 则提供了一种不可变、不拷贝的计划,即不提供 set 办法,子线程不须要拷贝就能够拜访父线程的变量。具体应用如下:
class Server {public final static ScopedValue<User> LOGGED_IN_USER = ScopedValue.newInstance();
private void serve(Request request) {
// ...
User loggedInUser = authenticateUser(request);
ScopedValue.where(LOGGED_IN_USER, loggedInUser)
.run(() -> restAdapter.processRequest(request));
// ...
}
}
通过 ScopedValue.where 能够绑定 ScopedValue 的值,而后在 run 办法里能够应用,办法执行结束自行开释,能够被垃圾收集器回收
JEP 432: Record Patterns (Second Preview)
JDK19 的 JEP 405: Record Patterns (Preview)将 Record 的模式匹配作为第一次 preview
JDK20 则作为第二次 preview
-
针对嵌套 record 的推断,能够这样
record Point(int x, int y) {} enum Color {RED, GREEN, BLUE} record ColoredPoint(Point p, Color c) {} record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {} static void printColorOfUpperLeftPoint(Rectangle r) {if (r instanceof Rectangle(ColoredPoint(Point p, Color c), ColoredPoint lr)) {System.out.println(c); } }
-
整体而言,模式匹配有如下几种:
Pattern: TypePattern ParenthesizedPattern RecordPattern TypePattern: LocalVariableDeclaration ParenthesizedPattern: (Pattern) RecordPattern: ReferenceType RecordStructurePattern RecordStructurePattern: ([ RecordComponentPatternList] ) RecordComponentPatternList : Pattern {, Pattern}
-
针对泛型推断
record Box<T>(T t) {} static void test1(Box<String> bo) {if (bo instanceof Box<String>(var s)) {System.out.println("String" + s); } }
也反对嵌套
static void test3(Box<Box<String>> bo) {if (bo instanceof Box<Box<String>>(Box(var s))) {System.out.println("String" + s); } }
JEP 433: Pattern Matching for switch (Fourth Preview)
在 JDK14JEP 305: Pattern Matching for instanceof (Preview)作为 preview
在 JDK15JEP 375: Pattern Matching for instanceof (Second Preview)作为第二轮的 preview
在 JDK16JEP 394: Pattern Matching for instanceof 转正
JDK17 引入 JEP 406: Pattern Matching for switch (Preview)
JDK18 的 JEP 420: Pattern Matching for switch (Second Preview) 则作为第二轮 preview
JDK19 的 JEP 427: Pattern Matching for switch (Third Preview)作为第三轮 preview
JDK20 作为第四轮 preview
自第三次预览以来的次要变动是:
- 针对枚举类型呈现无奈匹配的时候抛出 MatchException 而不是 IncompatibleClassChangeError
- 开关标签的语法更简略
- switch 当初反对 record 泛型的推断
以前针对 null 值 switch 会抛出异样,须要非凡解决
static void testFooBar(String s) {if (s == null) {System.out.println("Oops!");
return;
}
switch (s) {case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
当初能够间接 switch
static void testFooBar(String s) {switch (s) {case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
case when 的反对,以前这么写
class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape {int calculateArea() {...} }
static void testTriangle(Shape s) {switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}
当初能够这么写
static void testTriangle(Shape s) {switch (s) {
case null ->
{break;}
case Triangle t
when t.calculateArea() > 100 ->
System.out.println("Large triangle");
case Triangle t ->
System.out.println("Small triangle");
default ->
System.out.println("Non-triangle");
}
}
针对 record 泛型的类型推断:
record MyPair<S,T>(S fst, T snd){};
static void recordInference(MyPair<String, Integer> pair){switch (pair) {case MyPair(var f, var s) ->
... // Inferred record Pattern MyPair<String,Integer>(var f, var s)
...
}
}
JEP 434: Foreign Function & Memory API (Second Preview)
Foreign Function & Memory (FFM) API 蕴含了两个 incubating API
JDK14 的 JEP 370: Foreign-Memory Access API (Incubator)引入了 Foreign-Memory Access API 作为 incubator
JDK15 的 JEP 383: Foreign-Memory Access API (Second Incubator)Foreign-Memory Access API 作为第二轮 incubator
JDK16 的 JEP 393: Foreign-Memory Access API (Third Incubator)作为第三轮,它引入了 Foreign Linker API (JEP 389)
FFM API 在 JDK 17 的 JEP 412: Foreign Function & Memory API (Incubator)作为 incubator 引入
FFM API 在 JDK 18 的 JEP 419: Foreign Function & Memory API (Second Incubator) 作为第二轮 incubator
JDK19 的 JEP 424: Foreign Function & Memory API (Preview)则将 FFM API 作为 preview API
JDK20 作为第二轮 preview
应用示例
javac --release 20 --enable-preview ... and java --enable-preview ....
// 1. Find foreign function on the C library path
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle radixsort = linker.downcallHandle(stdlib.find("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings = { "mouse", "cat", "dog", "car"};
// 3. Use try-with-resources to manage the lifetime of off-heap memory
try (Arena offHeap = Arena.openConfined()) {
// 4. Allocate a region of off-heap memory to store four pointers
MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
// 5. Copy the strings from on-heap to off-heap
for (int i = 0; i < javaStrings.length; i++) {MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);
pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);
}
// 6. Sort the off-heap data by calling the foreign function
radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\0');
// 7. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
javaStrings[i] = cString.getUtf8String(0);
}
} // 8. All off-heap memory is deallocated here
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"}); // true
JEP 436: Virtual Threads (Second Preview)
在 JDK19https://openjdk.org/jeps/425)作为第一次 preview
在 JDK20 作为第二次 preview,此版本 java.lang.ThreadGroup 被永恒废除
应用示例
void handle(Request request, Response response) {
var url1 = ...
var url2 = ...
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {var future1 = executor.submit(() -> fetchURL(url1));
var future2 = executor.submit(() -> fetchURL(url2));
response.send(future1.get() + future2.get());
} catch (ExecutionException | InterruptedException e) {response.fail(e);
}
}
String fetchURL(URL url) throws IOException {try (var in = url.openStream()) {return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
}
JEP 437: Structured Concurrency (Second Incubator)
在 JDK19JEP 428: Structured Concurrency (Incubator)作为第一次 incubator
在 JDK20 作为第二次 incubator
JEP 438: Vector API (Fifth Incubator)
JDK16 引入了 JEP 338: Vector API (Incubator)提供了 jdk.incubator.vector 来用于矢量计算
JDK17 进行改良并作为第二轮的 incubatorJEP 414: Vector API (Second Incubator)
JDK18 的 JEP 417: Vector API (Third Incubator) 进行改良并作为第三轮的 incubator
JDK19JEP 426:Vector API (Fourth Incubator)作为第四轮的 incubator
JDK20 作为第五轮的 incubator
细项解读
下面列出的是大方面的个性,除此之外还有一些 api 的更新及废除,次要见 JDK 20 Release Notes,这里举几个例子。
增加项
- Support Unicode 15.0 Update Unicode Data Files to 15.0.0
- Add GarbageCollectorMXBean for Remark and Cleanup Pause Time in G1 JDK-8297247
移除项
- Thread.suspend/resume Changed to Throw UnsupportedOperationException JDK-8249627
- Thread.Stop Changed to Throw UnsupportedOperationException JDK-8289610
-
Improved Control of G1 Concurrent Refinement Threads JDK-8137022
以下这些参数将来版本移除
-XX:-G1UseAdaptiveConcRefinement -XX:G1ConcRefinementGreenZone=buffer-count -XX:G1ConcRefinementYellowZone=buffer-count -XX:G1ConcRefinementRedZone=buffer-count -XX:G1ConcRefinementThresholdStep=buffer-count -XX:G1ConcRefinementServiceIntervalMillis=msec
废除项
残缺列表见 Java SE 20 deprecated-list
-
java.net.URL Constructors Are Deprecated JDK-8294241
URL 的结构器被废除,能够应用 URL::of(URI, URLStreamHandler)工厂办法代替
已知问题
-
java.lang.Float.floatToFloat16 and java.lang.Float.float16ToFloat May Return Different NaN Results when Optimized by the JIT Compiler (JDK-8302976, JDK-8289551, JDK-8289552)
JDK20 引入了 java.lang.Float.floatToFloat16 及 java.lang.Float.float16ToFloat 办法,在 JIT 编译优化时可能会返回不同的 Nan 后果,能够应用如下参数禁用 JIT 对此的优化
-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_floatToFloat16,_float16ToFloat
其余事项
-
Disabled TLS_ECDH_* Cipher Suites (JDK-8279164)
TLS_ECDH_* cipher suites 默认被禁用了
- HTTP Response Input Streams Will Throw an IOException on Interrupt (JDK-8294047)
-
HttpClient Default Keep Alive Time is 30 Seconds (JDK-8297030)
http1.1 及 http2 的闲暇连贯的超时工夫从 1200 秒改为 30 秒
小结
Java20 次要有如下几个个性
- JEP 429: Scoped Values (Incubator)
- JEP 432: Record Patterns (Second Preview)
- JEP 433: Pattern Matching for switch (Fourth Preview)
- JEP 434: Foreign Function & Memory API (Second Preview)
- JEP 436: Virtual Threads (Second Preview)
- JEP 437: Structured Concurrency (Second Incubator)
- JEP 438: Vector API (Fifth Incubator)
doc
- JDK 20 Features
- JDK 20 Release Notes
- Consolidated JDK 20 Release Notes
- Java SE 20 deprecated-list
- The Arrival of Java 20
- JDK 20 G1/Parallel/Serial GC changes
- Java 20 Delivers Features for Projects Amber, Loom and Panama
- Java 20: a faster future is Looming
- JDK 20 Security Enhancements
- Project Loom’s Scoped Values: The Most Interesting New Java 20 Feature