前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java22的新特性

Java22的新特性

作者头像
code4it
发布2024-03-27 14:26:08
1540
发布2024-03-27 14:26:08
举报
文章被收录于专栏:码匠的流水账码匠的流水账

Java语言特性系列

本文主要讲述一下Java22的新特性

版本号

代码语言:javascript
复制
java -version
openjdk version "22" 2024-03-19
OpenJDK Runtime Environment (build 22+36-2370)
OpenJDK 64-Bit Server VM (build 22+36-2370, mixed mode, sharing)

从version信息可以看出是build 22+36

特性列表

JEP 423: Region Pinning for G1

主要是通过引入Region Pinning来降低使用JNI时G1收集器的延时。与Java代码不同,JNI交互可能使用指向堆中对象的显式指针。当Java线程执行JNI 代码的关键区域时,无法在堆中重新定位这些对象。为了避免此问题,G1在关键区域禁用GC,这可能会导致延迟增加,因为如果其他非JNI线程触发GC,它们将被阻止。此更改允许G1 GC通过固定JNI代码使用的内存区域但允许重新定位和收集其他内存区域,即使线程位于关键区域也可以运行。

JEP 447: Statements before super(…) (Preview)

作为一种面向对象的语言,Java 提供了扩展另一个(非最终)类并继承状态和行为(在允许的情况下)的能力。为了可靠地工作,必须以自上而下的顺序调用类的构造函数,以避免子类构造函数干扰超类构造函数。当开发人员决定显式调用超类构造函数时,这必须是第一个语句。这会带来一些限制,这可能会导致代码比预期的更复杂。其中最明显的是,在调用超类构造函数之前,无法对构造函数参数执行测试。如果测试导致引发异常,则对超类构造函数的调用在技术上将成为不必要的开销。 此JEP引入了一种在调用super之前允许语句的受控方法。

比如在JEP 447之前的代码如下:

代码语言:javascript
复制
public class PositiveBigInteger extends BigInteger {

    public PositiveBigInteger(long value) {
        super(value);               // Potentially unnecessary work
        if (value <= 0)
            throw new IllegalArgumentException(non-positive value);
    }

}

在JEP 447之后代码可以如下:

代码语言:javascript
复制
public class PositiveBigInteger extends BigInteger {

    public PositiveBigInteger(long value) {
        if (value <= 0)
            throw new IllegalArgumentException(non-positive value);
        super(value);
    }

}

JEP 454: Foreign Function & Memory API

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的JEP 434: Foreign Function & Memory API (Second Preview)作为第二轮preview JDK21的JEP 442: Foreign Function & Memory API (Third Preview)作为第三轮preview JDK22的JEP 454则正式发布此特性

使用示例

代码语言:javascript
复制
// 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.ofConfined()) {
    // 4. Allocate a region of off-heap memory to store four pointers
    MemorySegment pointers
        = offHeap.allocate(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.allocateFrom(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.reinterpret(...).getString(0);
    }
} // 8. All off-heap memory is deallocated here
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

JEP 456: Unnamed Variables & Patterns

Unnamed Patterns and Variables支持用_来替代没有使用的变量声明 JDK21的JEP 443: Unnamed Patterns and Variables (Preview)作为preview JDK22的JEP 456则正式发布

比如之前的代码是这样子:

代码语言:javascript
复制
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
    if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(String name, int roomSize))) {
        return timeInMs == roomSize;
    }
    return false;
}

使用此特性之后如下:

代码语言:javascript
复制
static boolean isDelayTimeEqualToReverbRoomSize(EffectLoop effectLoop) {
    if (effectLoop instanceof EffectLoop(Delay(int timeInMs), Reverb(_, int roomSize))) {
        return timeInMs == roomSize;
    }
    return false;
}

这里假设Reverb的name没有使用

其他示例1

代码语言:javascript
复制
int guitarCount = 0;
for (Guitar _ : guitars) {
    if (guitarCount < LIMIT) { 
        guitarCount++;
    }
}

其他示例2

代码语言:javascript
复制
var lesPaul = new Guitar("Les Paul");
try { 
    cart.add(stock.get(lesPaul, guitarCount));
} catch (OutOfStockException _) { 
    System.out.println("Sorry, out of stock!");
}

JEP 457: Class-File API (Preview)

JEP 457 提供了一个用于解析、生成和转换 Java 类文件的标准 API。此 API 处于预览状态。Java 生态系统有许多用于解析和生成 Java 类文件的库:ASM、BCEL、Javassist等大多数字节码生成框架都使用它们。Java类格式每6个月演化一次,每个新的Java版本都会发布,因此生成框架必须同时演进,否则可能会不支持最新的语言演进。JDK 本身使用ASM来实现它的一些工具,以及lambda实现,这在需要生成类文件的部分中,一个Java版本的功能与JVM中可以使用的功能之间存在差异,因为您必须等待支持版本 N 的新功能的 ASM 版本,然后才能在版本N+1中使用它们。类文件API通过在JDK中提供用于解析、生成和转换类文件的API来克服这个问题。

比如要生成如下方法

代码语言:javascript
复制
void fooBar(boolean z, int x) {
    if (z)
        foo(x);
    else
        bar(x);
}

用ASM的示例:

代码语言:javascript
复制
ClassWriter classWriter = ...;
MethodVisitor mv = classWriter.visitMethod(0, "fooBar", "(ZI)V", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 1);
Label label1 = new Label();
mv.visitJumpInsn(IFEQ, label1);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "Foo", "foo", "(I)V", false);
Label label2 = new Label();
mv.visitJumpInsn(GOTO, label2);
mv.visitLabel(label1);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "Foo", "bar", "(I)V", false);
mv.visitLabel(label2);
mv.visitInsn(RETURN);
mv.visitEnd();

使用此特性的示例:

代码语言:javascript
复制
ClassBuilder classBuilder = ...;
classBuilder.withMethod("fooBar", MethodTypeDesc.of(CD_void, CD_boolean, CD_int), flags,
                        methodBuilder -> methodBuilder.withCode(codeBuilder -> {
    Label label1 = codeBuilder.newLabel();
    Label label2 = codeBuilder.newLabel();
    codeBuilder.iload(1)
        .ifeq(label1)
        .aload(0)
        .iload(2)
        .invokevirtual(ClassDesc.of("Foo"), "foo", MethodTypeDesc.of(CD_void, CD_int))
        .goto_(label2)
        .labelBinding(label1)
        .aload(0)
        .iload(2)
        .invokevirtual(ClassDesc.of("Foo"), "bar", MethodTypeDesc.of(CD_void, CD_int))
        .labelBinding(label2);
        .return_();
});

JEP 458: Launch Multi-File Source-Code Programs

JDK11的JEP 330: Launch Single-File Source-Code Programs引入了直接运行单个源文件的能力,一个缺点是所有源代码都必须放在一个文件中。要处理多个文件,仍然需要单独的编译步骤,这迫使开发人员在其项目中使用构建工具。如果开发人员仍然是初学者,那么情况可能会更糟:他们必须暂停对语言的学习,并且必须优先考虑学习或构建 Maven 或 Gradle 等工具。 Java22引入了一个启动器,它支持运行由多个文件组成的程序。假设一个目录包含两个文件Prog.java及Helper.java,其中每个文件声明一个类

代码语言:javascript
复制
// Prog.java
class Prog {
    public static void main(String[] args) { Helper.run(); }
}

// Helper.java
class Helper {
    static void run() { System.out.println("Hello!"); }
}

运行java Prog.java会在内存编译Prog并执行其main方法,这里Prog引用了Helper类,则启动器会在文件系统查找Helper.java文件然后内存编译。

如果是引用了jar包的类,则可以通过--class-path lib/*来指定,比如

代码语言:javascript
复制
Prog1.java
Prog2.java
Helper.java
libs/
├─ library1.jar
├─ library2.jar

可以通过如下来启动

代码语言:javascript
复制
$ java --class-path 'lib/*' Prog1.java
$ java --class-path 'lib/*' Prog2.java

如果libs里头的是模块化的,则可以使用如下方式启动

代码语言:javascript
复制
$ java -p lib Prog1.java
$ java -p lib Prog2.java

JEP 459: String Templates (Second Preview)

JDK21的JEP 430: String Templates (Preview)引入了String Templates JDK22作为第二次preview

使用示例

代码语言:javascript
复制
String title = "My Online Guitar Store";
String text = "Buy your next Les Paul here!";
String html = STR."""
        <html>
          <head>
            <title>\{title}</title>
          </head>
          <body>
            <p>\{text}</p>
          </body>
        </html>
        """;

JEP 460: Vector API (Seventh 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 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则作为第七轮的incubator,使用示例如下

代码语言:javascript
复制
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;
   }
}

static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;

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 461: Stream Gatherers (Preview)

JDK22针对stream引入了gather操作,允许用户自定义中间操作,比如自定义distinctBy操作

代码语言:javascript
复制
guitars.stream()
        .gather(distinctBy(Guitar::guitarStyle))
        .forEach(System.out::println);

static <T, A> Gatherer<T, ?, T> distinctBy(Function<? super T, ? extends A> classifier) {
    Supplier<Map<A, List<T>>> initializer = HashMap::new;
    Gatherer.Integrator<Map<A, List<T>>, T, T> integrator = (state, element, _) -> {
        state.computeIfAbsent(classifier.apply(element), _ -> new ArrayList<>()).add(element);
        return true; // true, because more elements need to be consumed
    };
    BiConsumer<Map<A, List<T>>, Gatherer.Downstream<? super T>> finisher = (state, downstream) -> {
        state.forEach((_, value) -> downstream.push(value.getLast()));
    };
    return Gatherer.ofSequential(initializer, integrator, finisher);
}        

这里展示了使用gather的几个func:initializer(可选,用于维护状态)、integrator(用于集成输入)、combiner(可选,用于组合并行流)、finisher(可选,当stream没有输入的时候执行)

java.util.stream.Gatherers内置了如下几个操作:fold、mapConcurrent、scan、windowFixed、windowSliding

JEP 462: Structured Concurrency (Second Preview)

JDK19的JEP 428: Structured Concurrency (Incubator)作为第一次incubator JDK20的JEP 437: Structured Concurrency (Second Incubator)作为第二次incubator JDK21的JEP 453: Structured Concurrency (Preview)作为首次preview JDK22作为第二次preview,使用示例如下

代码语言:javascript
复制
Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Supplier<String>  user  = scope.fork(() -> findUser());
        Supplier<Integer> order = scope.fork(() -> fetchOrder());

        scope.join()            // Join both subtasks
             .throwIfFailed();  // ... and propagate errors

        // Here, both subtasks have succeeded, so compose their results
        return new Response(user.get(), order.get());
    }
}

JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)

JDK21的JEP 445: Unnamed Classes and Instance Main Methods (Preview)作为首次preview,引入了未命名的类和实例main方法特性可以简化hello world示例,方便java新手入门 JDK22作为第二次preview,它支持了更为灵活的程序启动协议,比如允许启动类的方法有public、protected权限,如果启动类包含参数方法则会选择有参数的,否则选择无参的main方法。

示例如下

代码语言:javascript
复制
        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");
        }

javac --release 21 --enable-preview Main.javajava --enable-preview Main 其中main方法选择的优先顺序是static的优于非static的,然后有args的优于没有args的

JEP 464: Scoped Values (Second Preview)

JDK20的JEP 429: Scoped Values (Incubator)作为Incubator JDK21的JEP 446: Scoped Values (Preview)作为preview版本 JDK22作为第二次preview,具体使用如下:

代码语言:javascript
复制
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方法里可以使用,方法执行完毕自行释放,可以被垃圾收集器回收

细项解读

上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 22 Release Notes,这里举几个例子。

添加项

  • New Security Category for -XshowSettings Launcher Option(JDK-8281658)

XshowSettings新增了安全相关的设置,比如

代码语言:javascript
复制
   -XshowSettings:security
       show all security settings and continue
   -XshowSettings:security:*sub-category*
       show settings for the specified security sub-category and continue. Possible *sub-category* arguments for this option include:
       all: show all security settings and continue
       properties: show security properties and continue
       providers: show static security provider settings and continue
       tls: show TLS related security settings and continue
  • Support Unicode 15.1(JDK-8296246)

支持了unicode 15.1版本

  • Add equiDoubles() Method to java.util.random.RandomGenerator(JDK-8302987)
  • G1: Balance Code Root Scan Phase during Garbage Collection(JDK-8315503)
  • G1: Fast Collection of Evacuation Failed Regions(JDK-8140326)
  • Add a Built-in Catalog to JDK XML Module(JDK-8306055)

移除项

  • sun.misc.Unsafe.shouldBeInitialized and ensureClassInitialized Are Removed(JDK-8316160)
  • Thread.countStackFrames Has Been Removed(JDK-8309196)
  • The Old Core Reflection Implementation Has Been Removed(JDK-8305104)
  • Jdeps -profile and -P Option Have Been Removed(JDK-8310460)

废弃项

  • Deprecation of the jdk.crypto.ec Module(JDK-8308398)
  • sun.misc.Unsafe park, unpark, getLoadAverage, and xxxFence Methods Are Deprecated for Removal(JDK-8315938)
  • -Xnoagent Option Is Deprecated for Removal(JDK-8312072)
  • -Xdebug and -debug Options Are Deprecated for Removal(JDK-8227229)

重要bug修复

  • Reimplement MethodHandleProxies::asInterfaceInstance(JDK-6983726)
  • MethodHandles.Lookup::findStaticVarHandle Does Not Eagerly Initialize the Field’s Declaring Class(JDK-8291065)
  • G1: More Deterministic Heap Resize at Remark(JDK-8314573)
  • The javac Compiler Should Not Accept Private Method References with a Type Variable Receiver(JDK-8318160)

已知问题

  • Java Terminates Unexpectedly on Apple silicon Systems With macOS 14.4(JDK-8327860)
  • JFR: Increased Startup Time when Using -XX:StartFlightRecording(JDK-8319551)
  • JVM May Crash or Malfunction When Using ZGC and Non-Default ObjectAlignmentInBytes(JDK-8325074)

其他事项

  • Added Certigna Root CA Certificate(JDK-8314960)
  • AWT SystemTray API Is Not Supported on Most Linux Desktops(JDK-8322750)
  • java.io.File Drops the Windows Long Path Prefix from Path Strings(JDK-8287843)
  • jdk.internal.vm.compiler Renamed to jdk.graal.compiler(JDK-8318027)
  • Allow JIT Compilation for -Xshare:dump(JDK-8305753)
  • NMT: Make Peak Values Available in Release Builds(JDK-8317772)
  • Add -XX:UserThreadWaitAttemptsAtExit=<number_of_waits>(JDK-8314243)
  • The Linux Specific Options UseSHM and UseHugeTLBFS Are Now Obsolete(JDK-8261894)
  • Two Phase Segmented Heap Dump(JDK-8306441)

小结

Java22主要有如下几个特性

  • JEP 423: Region Pinning for G1
  • JEP 447: Statements before super(…) (Preview)
  • JEP 454: Foreign Function & Memory API
  • JEP 456: Unnamed Variables & Patterns
  • JEP 457: Class-File API (Preview)
  • JEP 458: Launch Multi-File Source-Code Programs
  • JEP 459: String Templates (Second Preview)
  • JEP 460: Vector API (Seventh Incubator)
  • JEP 461: Stream Gatherers (Preview)
  • JEP 462: Structured Concurrency (Second Preview)
  • JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)
  • JEP 464: Scoped Values (Second Preview)

对业务开发比较有用的是Stream Gather特性、Structured Concurrency特性

doc

  • JDK 22 Features
  • JDK 22 Release Notes
  • Consolidated JDK 22 Release Notes
  • Java SE 22 deprecated-list
  • The Arrival of Java 22
  • JDK 22 G1/Parallel/Serial GC changes
  • Java 22 Delivers Foreign Memory & Memory API, Unnamed Variables & Patterns, and Return of JavaOne
  • JDK 22 and JDK 23: What We Know So Far
  • JDK 22, an Average Release (Sort of)
  • Java 22 Is Here, And It’s Ready To Rock
  • Java 22: What’s New?
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-03-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 版本号
  • 特性列表
    • JEP 423: Region Pinning for G1
      • JEP 447: Statements before super(…) (Preview)
        • JEP 454: Foreign Function & Memory API
          • JEP 456: Unnamed Variables & Patterns
            • JEP 457: Class-File API (Preview)
              • JEP 458: Launch Multi-File Source-Code Programs
                • JEP 459: String Templates (Second Preview)
                  • JEP 460: Vector API (Seventh Incubator)
                    • JEP 461: Stream Gatherers (Preview)
                      • JEP 462: Structured Concurrency (Second Preview)
                        • JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)
                          • JEP 464: Scoped Values (Second Preview)
                          • 细项解读
                            • 添加项
                              • 移除项
                                • 废弃项
                                  • 重要bug修复
                                    • 已知问题
                                      • 其他事项
                                      • 小结
                                      • doc
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档