
虽然多数人还是使用 Java 8,但并没有阻挡 Java 更新的脚步,最近 Java 23 发布了。今天来聊一聊 Java 8 到 java 23 增加了哪些新特性。
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
if (obj instanceof String s) {
//这里可以使用 s 变量
} else {
//这里不能使用 s 变量
}
Object o;
switch (o) {
case null -> System.out.println("首先判断对象是否为空,走空指针逻辑等后续逻辑");
case String s -> System.out.println("判断是否为字符串,s:" + s);
case record p -> System.out.println("判断是否为Record类型: " + p.toString());
case int[] arr -> System.out.println("判断是否为数组,展示int数组的长度" + ia.length);
case Integer i -> System.out.println("判断是否为Intger对象,i:" + i);
case Student s -> System.out.println("判断是否为具体学生对象,student:" + s.toString());
case UserCommonService -> System.out.println("判断是否为普通用户实现类,然后走普通用户逻辑");
case UserVipService -> System.out.println("判断是否为vip用户实现类,然后走vip用户逻辑");
default -> System.out.println("Something else");
}
/**
* The following code shows how to use {@code Optional.isPresent}:
* {@snippet :
* if (v.isPresent()) {
* System.out.println("v: " + v.get());
* }
* }
*/
//不使用向量 API 的写法:
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;
}
}
//使用向量 API 写法:
void vectorComputation(float[] a, float[] b, float[] c) {
for (int i = 0; i < a.length; i += SPECIES.length()) {
// VectorMask<Float> m;
var m = SPECIES.indexInRange(i, a.length);
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(va)
.add(vb.mul(vb))
.neg();
vc.intoArray(c, i, m);
}
}
Java 19 引入的主要是预览和孵化的新特性,包括:Record模式、将 JDK 移植到 Linux/RISC-V、外部函数和内存API、虚拟线程、向量API、模式匹配的 Switch、使用结构化并发方式实现并发编程。
下面主要看看一下向量 API。实例代码如下:
//不使用向量 API 的写法:
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;
}
}
//使用向量 API 写法:
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;
void vectorComputation(float[] a, float[] b, float[] c) {
for (int i = 0; i < a.length; i += SPECIES.length()) {
// VectorMask<Float> m;
var m = SPECIES.indexInRange(i, a.length);
// FloatVector va, vb, vc;
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(va)
.add(vb.mul(vb))
.neg();
vc.intoArray(c, i, m);
}
}
Java 20 引入的都是孵化和预览功能,下面简单看一下:
Java 21 是一个 LTS 版本,新增特性比较多,其中预览和孵化特性包括:
正式特性包括:
WARNING: A {Java,JVM TI} agent has been loaded dynamically (file:/u/bob/agent.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called implicitly, and waits
//Java 21 以前
static String formatter(Object obj) {
String formatted = "unknown";
if (obj instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (obj instanceof Long l) {
formatted = String.format("long %d", l);
} else if (obj instanceof Double d) {
formatted = String.format("double %f", d);
} else if (obj instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
//Java 21 以后
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
}
再看一下对 null 判断的简化:
// Prior to Java 21
static void testFooBarOld(String s) {
if (s == null) {
System.out.println("Oops!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
// As of Java 21
static void testFooBarNew(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
除此之外,switch 模式匹配还有很多内容,具体可以看下面的链接:
https://openjdk.org/jeps/441
// As of Java 16
record Point(int x, int y) {}
static void printSum(Object obj) {
if (obj instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// As of Java 21
static void printSum(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
}
}
更多精彩的示例见下面链接:
https://openjdk.org/jeps/440
Java 22 引入孵化和预览的特性如下:
//之前的写法
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(value); // Potentially unnecessary work
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
}
}
//使用前导语句的写法
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
super(value);
}
}
source.gather(a).gather(b).gather(c).collect(...)
class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}
Java 22 引入的正式特性包括:
Prog1.java
Prog2.java
Helper.java
library1.jar
library2.jar
下面命令('*')可以把在目录下面的 jar 包都放到 classpath,以方便地运行 Java 程序。
java --class-path '*' Prog1.java
//使用未命名变量之前
Queue<Integer> q = ... // x1, y1, z1, x2, y2, z2 ..
while (q.size() >= 3) {
int x = q.remove();
int y = q.remove();
int z = q.remove(); // z is unused
... new Point(x, y) ...
}
//使用未命名变量之后
while (q.size() >= 3) {
var x = q.remove();
var _ = q.remove(); // Unnamed variable
var _ = q.remove(); // Unnamed variable
... new Point(x, 0) ...
}
Java 23 引入孵化和预览的特性如下:
import module java.sql
//下面是之前的写法
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(value); // Potentially unnecessary work
if (value <= 0) throw new IllegalArgumentException(..);
}
}
//使用灵活构造函数体后,写法变成
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0) throw new IllegalArgumentException(..);
super(value);
}
}
Java 23 引入的正式特性包括:
/// 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
其实每个 Java 版本发布的新特性并不多,而且好多特性要进行多个版本的孵化和预览。虽然公司的 Java 版本肯定跟不上 Java 版本发布的节奏,但作为程序员的我们,可以关注下 Java 的新增特性。
推荐阅读:
Java 23 发布,人麻了。。。 京东二面:Java中一共有 N 种实现锁的方式,你知道都有哪些吗? 美团一面:RocketMQ消费者消费的时候,宕机了,消息会丢失吗? 面试时候说RPC是协议?今天的面试就到这里,你先回去等通知吧。 电话普及二十年后,年轻人开始害怕接电话。