Java 23 新特性 (EOL)
生命周期结束时间(EOL): 2025/03/16
官方发布介绍页面:https://openjdk.org/projects/jdk/23/
1. JEP 455:模式、instanceof 和 switch 中的基本数据类型(预览版)
使用 instanceof 和 switch,我们可以检查某个对象是否属于某类型,如果是则将该对象绑定到该类型的变量,执行特定的程序路径,并在该程序路径中使用新变量。
例如,以下代码块已经在 Java 16 启用,检查对象是否为至少包含 5 个字符的字符串,如果是则以大写形式打印。如果对象是整数,则计算该数字的平方并打印。否则,按原样打印对象。
if (obj instanceof String s && s.length() >= 5) {
System.out.println(s.toUpperCase());
} else if (obj instanceof Integer i) {
System.out.println(i * i);
} else {
System.out.println(obj);
}
而在 Java 21 中,我们可以使用switch更加容易的改变上面的写法
baseConsumer.registerConsumer("messageCenter-out-0", message -> {
log.info(STR."收到消息:\{message}");
Objects.requireNonNull(message.getContentClassName(), "消息体类型不能为空");
Class<? extends BaseMessage> messageBodyClass = null;
try {
//noinspection unchecked
messageBodyClass = (Class<? extends BaseMessage>) Class.forName(message.getContentClassName());
} catch (ClassNotFoundException e) {
log.error(STR."消息体类型不存在:\{message.getContentClassName()}", e);
}
BaseMessage baseMessage = message.getBody(messageBodyClass);
return switch (baseMessage) {
case DingTalkInfo dingTalkInfo -> dingTalkMessageHandler.doBusiness(dingTalkInfo);
case NotificationInfo notificationInfo -> notificationMessageHandler.doBusiness(notificationInfo);
case MailInfo mailInfo -> emailMessageHandler.doBusiness(mailInfo);
case WorkWechatMessageInfo wechatMessageInfo -> workWechatMessageHandler.doBusiness(wechatMessageInfo);
case null, default -> {
log.error(STR."消息体类型不支持:\{message.getContentClassName()}");
yield false;
}
};
});
而以上的特性仅适用于对象操作,instanceof根本不能与基元数据类型一起使用,只在可以将基元类型byte、short、char和int的变量与常量匹配的范围内进行切换,例如:
int x = ...
switch (x) {
case 1, 2, 3 -> System.out.println("Low");
case 4, 5, 6 -> System.out.println("Medium");
case 7, 8, 9 -> System.out.println("High");
}
JEP-455 的提案就是让所有基本类型现在也可以在 Java 23 的模式匹配中使用,包括instanceof和switch。
- 首先,所有基本类型现在都可以在
switch表达式和语句中使用,包括long、float、double和boolean。 - 其次,我们还可以在模式匹配中使用所有原始类型,包括
instanceof和switch。
instanceof:
int value = 65;
if (value instanceof byte b) System.out.println(value + " instanceof byte: " + b);
if (value instanceof short s) System.out.println(value + " instanceof short: " + s);
if (value instanceof int i && i > 1) System.out.println(value + " instanceof int: " + i);
if (value instanceof long l && l > 5L) System.out.println(value + " instanceof long: " + l);
if (value instanceof float f) System.out.println(value + " instanceof float: " + f);
if (value instanceof double d) System.out.println(value + " instanceof double: " + d);
if (value instanceof char c) System.out.println(value + " instanceof char: " + c);
switch:
double value = ...
switch (value) {
case 1 -> ...
case 2 -> ...
case int i when i < 100 -> ...
case int i -> ...
default -> ...
}
类型判断:
double value = ...
switch (value) {
case byte _ -> System.out.println(value + " instanceof byte");
case int _ -> System.out.println(value + " instanceof int");
case double _ -> System.out.println(value + " instanceof double");
}
在基本类型判断上,我们需要注意,如果将byte位置放到int之后,可能会导致永远不会匹配,因为每个字节也都是一个int,因此会由case int标签处理。
如果要用switch进行基本类型判断,那么我们就需要完整覆盖全部的类型,比如:当前有一个变量float value = 0.5f,如果上例中去掉最后一个double,编译器将返回消息“switch语句未覆盖所有可能的输入值”,因为double可以覆盖float类型,以此类推,当存在int的时候则可以覆盖byte和short等。
JEP 466:类文件API(Class File API)(第二次预览)
JDK22的JEP 457: Class-File API (Preview)提供了一个用于解析、生成和转换 Java 类文件的标准 API。本次为第二次
JEP 467:Markdown文档注释
JDK 23引入了Markdown文档注释,允许JavaDoc文档注释使用Markdown语法。这使得API文档注释的编写和阅读更加简洁易懂,并扩展了编译器树API,以便其他工具可以处理Markdown内容。
之前HTML语法的文档注释
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@link
* #equals(Object) equals} method, then calling the {@code
* hashCode} method on each of the two objects must produce the
* same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link #equals(Object) equals} method, then
* calling the {@code hashCode} method on each of the two objects
* must produce distinct integer results. However, the programmer
* should be aware that producing distinct integer results for
* unequal objects may improve the performance of hash tables.
* </ul>
*
* @implSpec
* As far as is reasonably practical, the {@code hashCode} method defined
* by class {@code Object} returns distinct integers for distinct objects.
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
JDK 23内新增的Markdown文档注释
/// Returns a hash code value for the object. This method is
/// supported for the benefit of hash tables such as those provided by
/// [java.util.HashMap].
///
/// The general contract of `hashCode` is:
///
/// - Whenever it is invoked on the same object more than once during
/// an execution of a Java application, the `hashCode` method
/// must consistently return the same integer, provided no information
/// used in `equals` comparisons on the object is modified.
/// This integer need not remain consistent from one execution of an
/// application to another execution of the same application.
/// - If two objects are equal according to the
/// [equals][#equals(Object)] method, then calling the
/// `hashCode` method on each of the two objects must produce the
/// same integer result.
/// - It is _not_ required that if two objects are unequal
/// according to the [equals][#equals(Object)] method, then
/// calling the `hashCode` method on each of the two objects
/// must produce distinct integer results. However, the programmer
/// should be aware that producing distinct integer results for
/// unequal objects may improve the performance of hash tables.
///
/// @implSpec
/// As far as is reasonably practical, the `hashCode` method defined
/// by class `Object` returns distinct integers for distinct objects.
///
/// @return a hash code value for this object.
/// @see java.lang.Object#equals(java.lang.Object)
/// @see java.lang.System#identityHashCode
新的文档注释写法需要以///开头来表示使用markdown的语法
JEP 469:Vector API
Vector API 允许在 Java 中进行矢量计算。
- JDK16 引入了 JEP 338: Vector API (Incubator) 提供了
jdk.incubator.vector来用于矢量计算- JDK17 进行改进并作为第二轮的incubator JEP 414: Vector API (Second Incubator)
- JDK18 的 JEP 417: Vector API (Third Incubator) 进行改进并作为第三轮的 incubator
- JDK19 的 JEP 426:Vector API (Fourth Incubator) 作为第四轮的 incubator
- JDK20 的 JEP 438: Vector API (Fifth Incubator) 作为第五轮的 incubator
- JDK21 的 JEP 448: Vector API (Sixth Incubator) 作为第六轮的 incubator
- JDK22 的 JEP 460: Vector API (Seventh Incubator) 作为第七轮的 incubator
- JDK23 的 JEP 469: Vector API (Eighth Incubator) 作为第八轮 incubator
import jdk.incubator.vector.*;
public class VectorExample {
private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
public void scalarComputation(float[] a, float[] b, float[] c) {
for (int i = 0; i < a.length; i++) {
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
}
}
public void vectorComputation(float[] a, float[] b, float[] c) {
int i = 0;
int upperBound = SPECIES.loopBound(a.length);
for (; i < upperBound; i += SPECIES.length()) {
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i);
var vb = FloatVector.fromArray(SPECIES, b, i);
var vc = va.mul(va)
.add(vb.mul(vb))
.neg();
vc.intoArray(c, i);
}
for (; i < a.length; i++) {
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
}
}
}
JEP 473:流收集器 (Stream Gatherers) (第二次预览)
- JDK22 的 JEP 461: Stream Gatherers (Preview) 作为第1次预览
- JDK23 的 JEP 473: Stream Gatherers (Second Preview) 作为第2次预览
static <TR> Gatherer<TR, ?, TR> selectOne(BinaryOperator<TR> selector) {
// Validate input
Objects.requireNonNull(selector, "selector must not be null");
// Private state to track information across elements
class State {
TR value; // The current best value
boolean hasValue; // true when value holds a valid value
}
// Use the `of` factory method to construct a gatherer given a set
// of functions for `initializer`, `integrator`, `combiner`, and `finisher`
return Gatherer.of(
// The initializer creates a new State instance
State::new,
// The integrator; in this case we use `ofGreedy` to signal
// that this integerator will never short-circuit
Gatherer.Integrator.ofGreedy((state, element, downstream) -> {
if (!state.hasValue) {
// The first element, just save it
state.value = element;
state.hasValue = true;
} else {
// Select which value of the two to save, and save it
state.value = selector.apply(state.value, element);
}
return true;
}),
// The combiner, used during parallel evaluation
(leftState, rightState) -> {
if (!leftState.hasValue) {
// If no value on the left, return the right
return rightState;
} else if (!rightState.hasValue) {
// If no value on the right, return the left
return leftState;
} else {
// If both sides have values, select one of them to keep
// and store it in the leftState, as that will be returned
leftState.value = selector.apply(leftState.value,
rightState.value);
return leftState;
}
},
// The finisher
(state, downstream) -> {
// Emit the selected value, if there is one, downstream
if (state.hasValue)
downstream.push(state.value);
}
);
}
使用示例:
jshell> Stream.generate(() -> ThreadLocalRandom.current().nextInt())
.limit(1000) // Take the first 1000 elements
.gather(selectOne(Math::max)) // Select the largest value seen
.parallel() // Execute in parallel
.findFirst() // Extract the largest value
$1 ==> Optional[99822]
JEP 471:废弃 sun.misc.Unsafe 中的内存访问方法方法
本特性是为了废弃sun.misc.Unsafe中的内存访问特效,以便后续版本移除。
JEP 474:ZGC分代回收模式设置为默认ZGC
本特性将ZGC的分代回收设置为默认的模式,并将非分代的模式废弃以便后续移除。以前需要-XX:+UseZGC -XX:+ZGenerational开启分代,JDK23及以后版本就不需要显示使用-XX:+ZGenerational参数了。
JEP 476:模块导入声明(预览)
与JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)类似,本特性主要是为了简化语法方便新手使用,通过新引入module的import,来一次性导入module下所有package底下的类,示例:
import module java.base; // 包含了import java.io.*; import java.util.*;
import module java.base; // exports java.util, which has a public Date class
import module java.sql; // exports java.sql, which has a public Date class
import java.sql.Date; // resolve the ambiguity of the simple name Date!
...
Date d = ... // Ok! Date is resolved to java.sql.Date
...
JEP 477: 隐式声明类和实例主方法 (第三次预览)
示例代码:
static void main(String[] args) {
System.out.println("static main with args");
}
static void main() {
System.out.println("static main without args");
}
void main(String[] args) {
System.out.println("main with args");
}
void main() {
System.out.println("main with without args");
}
其中main方法选择的优先顺序是static的优于非static的,然后有args的优于没有args的。
JEP 480: 结构化并发(第三次预览)
与JDK22中的内容一致。
JEP 481:作用域值(第三次预览)
Scoped Values 提供了一种在特定范围内共享数据的方式,类似于线程本地变量。
import jdk.incubator.concurrent.ScopedValue;
public class ScopedValuesExample {
private static final ScopedValue<String> SCOPED_VALUE = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.where(SCOPED_VALUE, "Hello, Scoped Value!")
.run(() -> System.out.println(SCOPED_VALUE.get()));
}
}
JEP 482:灵活的构造函数体(第二次预览)
灵活的构造函数体在JDK 23中进行第二次预览。这个特性允许在显式调用构造函数之前初始化字段,使得构造函数的逻辑表达更为自然,同时保证构造函数在类实例化时按自上而下的顺序运行。