4小时前  Java系列 |   抢沙发  1 
文章评分 0 次,平均分 0.0

Java 24标志着该语言和JVM发展的新阶段,Leyden和Lilliput项目逐渐融入其中。性能优化、内存使用减少、启动速度加快:这些进步为更流畅、更高效的体验铺平了道路。虽然目前没有重大的语法变革计划,但一些预览功能仍在不断成熟,同时后量子加密算法的出现也增强了安全性。接下来,我们将探讨将塑造Java未来的新功能。

在Java领域,每个演进(称为JEP)可以有以下模式之一:

  • 孵化器:孵化器模块是一种将非确定性API和工具提供给开发者的方式。这些特性可能会在版本之间发生显著变化,甚至可能消失。
  • 实验性:这些功能目前正在测试中,默认情况下处于禁用状态(它们可能会被停用或完全重新设计)。
  • 预览版:这些功能已完全指定并实现,目前处于测试阶段,用户可启用以收集反馈。因此,这些功能可能会发生变化,不建议在生产环境中使用。
  • 标准:标准功能已准备好用于生产。

Java 24:Leyden和Liliput项目的逐步整合

与OpenJDK并行,许多项目都致力于实现特定的目标。近年来,随着来自Loom和Valhalla项目的Java增强提案(JEPs)的出现,Java 24正在逐步整合莱顿和小人国计划。

Leyden和Liliput项目

Leyden项目旨在优化Java应用程序的启动时间,减少其内存占用,并提高其整体性能。而Liliput项目则专注于Java对象头的管理,以减少所有工作负载的CPU和内存使用。

Valhalla和Loom项目

Valhalla项目为自己设定了一个雄心勃勃的目标,即彻底重新思考Java的对象模型。Java 23通过引入值类和值对象,已经让我们对此有所了解。其他进展则涉及原始类型和泛型类型的演进。

至于Loom,它确实产生了影响,尤其是在Java 21中引入了Virtual Threads之后。实现这些特性需要对JVM的内部工作机制进行全面改革。

Java 24:语言演进

Java 24并未引入任何重大新特性,但扩展了几个JEP(Java Enhancement Proposal,Java增强提案)作为预览版,以鼓励用户提供反馈。

JEP 488:模式、实例化类型检查和 switch 中的基本类型(第二版预览)

该特性最初在 Java 23(JEP 455)中作为预览版推出,之后未经修改进行了扩展。它允许在模式、实例化类型检查和 switch 中使用基本类型。

int x = 65;
if (x instanceof char c) {
  System.out.println("c = " + c); // Sortie : "c = A"
}

JEP 492:灵活的构造器体(第三版预览)

此特性在Java 22(JEP 447)中引入,允许在调用super()之前执行指令。Java 23对其进行了增强,支持赋值操作(JEP 482)。在Java 24中,该特性已更新至第三个预览版,但无重大更改。

public class PositiveBigInteger extends BigInteger {
  private final long max;

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

JEP 494:模块导入声明(第二版预览)

该特性在Java 23(JEP 476)中作为预览版推出,允许您通过import module M导入模块导出的包中的所有类。Java 24已进行了第二次预览版更新,以收集更多用户反馈。

import module java.util;

String[] fruits = new String[] { "apple", "berry", "citrus" };
Map<String, String> m =
    Stream.of(fruits)
          .collect(Collectors.toMap(s -> s.toUpperCase().substring(0,1),
                                    Function.identity()));

JEP 495:简单源文件和实例主方法(第四版预览)

这是该特性的第四个预览版,其初步步骤在Java 21(JEP 445)中首次引入。它简化了源文件的创建和main方法的编写。例如,一个简单的HelloWorld程序可以被简化,使您能够掌握语言的基础知识,而无需处理更复杂的概念,如类、static关键字或可见性。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

可以简化为:

main() {
  println("Hello, World!");
}

为了促进这种简化,Java语言已经做出了几处更改:

  • 主类不再需要声明为公共静态类。
  • 对于简单的文件,声明类不再是强制性的。
  • 对于简单的文件,会自动导入java.lang包中的许多特性,因此无需指定System.out.println;只需使用println即可。

Java 24:API开发

472:准备限制JNI的使用

自Java 22以来,可以通过Java本地接口(JNI)或外部函数与内存(FFM)API来调用本机代码。但是,FFM API中的本机代码加载受到限制,默认情况下会触发运行时警告。

为确保JNI和FFM之间的一致性,通过JNI进行的本机代码调用在运行时也会生成一条警告。

以下是使用JNI或FFM API时返回的消息:

WARNING: A restricted method in java.lang.foreign.Linker has been called
WARNING: java.lang.foreign.Linker::downcallHandle has been called by com.example.Main in an unnamed module
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled

要禁用所有Java代码的警告消息,请使用选项 --enable-native-access=ALL-UNNAMED:

java --enable-native-access=ALL-UNNAMED ...

484:类文件API

在Java 22(JEP 457)中作为预览版引入,并在Java 23(JEP 466)中进行了修订,此功能支持直接操作Java类文件。以下是一个示例,我们希望在类文件中生成以下方法:

void fooBar(boolean z, int x) {
    if (z)
        foo(x);
    else
        bar(x);
}

以下代码展示了如何使用Builder生成方法,突出了API特定且透明的代码生成方式:

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 485:流收集器

该特性最初在Java 22(JEP 461)中预览,并延续到Java 23(JEP 473),允许您为流创建自定义中间操作。请注意,之前已经可以通过Collector接口定义自定义终端操作。

以下是一个示例,用于说明中间操作符 Gatherers.limit() 的工作原理。

Gatherer<String, ?, String> limit() {
  class Counter {
    int counter;
    Counter(int counter) { this.counter = counter; }
  }
  return Gatherer.ofSequential(
      () -> new Counter(0),
      (counter, element, downstream) -> {
        if (counter.counter++ == 3) {
          return false;
        }
        return downstream.push(element);
      }
  );
}

然而,创建自定义中间操作来重现已存在操作的等效功能,如上述的limit()示例,效率较低。事实上,这些自定义操作无法从即时编译(Just-In-Time,JIT)优化中受益。

安全性:后量子加密

2024年8月,美国国家标准与技术研究院(NIST)发布了一套专门设计用于抵御量子计算机攻击的加密和签名工具。这些后量子算法标准旨在保护从机密电子邮件到电子商务交易等一系列广泛的电子信息。针对这一发展,Java 24已将其中两种算法集成到其库中,以增强长期数据安全性。

496:基于模块格的量子抗性密钥封装机制

联邦信息处理标准(FIPS)203被设计为主要通用加密标准。该标准基于CRYSTALS-Kyber算法,该算法被重命名为ML-KEM,即基于模块格的密钥封装机制。

// Génération de paire de clés par defaut
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM");
KeyPair kp = g.generateKeyPair(); // an ML-KEM-768 key pair

// Initialisation avec l'algorithme ML-KEM-512
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM");
g.initialize(NamedParameterSpec.ML_KEM_512);
KeyPair kp = g.generateKeyPair(); // an ML-KEM-512 key pair

// Instancier directement un KeyPairGenerator ML-KEM-1024
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM-1024");
KeyPair kp = g.generateKeyPair(); // an ML-KEM-1024 key pair

// Encapsuler une clé
KEM ks = KEM.getInstance("ML-KEM");
KEM.Encapsulator enc = ks.newEncapsulator(publicKey);
KEM.Encapsulated encap = enc.encapsulate();
byte[] msg = encap.encapsulation();     // send this to receiver
SecretKey sks = encap.key();

// Désencapsuler une clé
byte[] msg = ...;                       // received from sender
KEM kr = KEM.getInstance("ML-KEM");
KEM.Decapsulator dec = kr.newDecapsulator(privateKey);
SecretKey skr = dec.decapsulate(msg);

497:抗量子模块格基数字签名算法FIPS

204旨在成为保护电子签名的主要标准。该标准采用CRYSTALS-Dilithium算法,该算法已更名为ML-DSA,即模块格基数字签名算法的缩写。

// Génération de paire de clés par defaut
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA");
KeyPair kp = g.generateKeyPair(); // an ML-DSA-65 key pair

// Initialisation avec l'algorithme ML-DSA-44
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA");
g.initialize(NamedParameterSpec.ML_DSA_44);
KeyPair kp = g.generateKeyPair(); // an ML-DSA-44 key pair

// Instancier directement un KeyPairGenerator ML-DSA-87
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA-87");
KeyPair kp = g.generateKeyPair(); // an ML-DSA-87 key pair

// Signer un message avec une clé privée
byte[] msg = ...;
Signature ss = Signature.getInstance("ML-DSA");
ss.initSign(privateKey);
ss.update(msg);
byte[] sig = ss.sign();

// Vérifier une signature avec une clé publique
byte[] msg = ...;
byte[] sig = ...;
Signature sv = Signature.getInstance("ML-DSA");
sv.initVerify(publicKey);
sv.update(msg);
boolean verified = sv.verify(sig);

JEP 498:在sun.misc.Unsafe中使用内存访问方法时发出警告

此特性的目的是为通过sun.misc.Unsafe API(该API于2002年引入)移除内存访问方法做好生态系统准备。

现在,当应用程序直接或间接使用这些方法时,会发出警告。

尽管这些方法在Java 23中已经被弃用,但Java 24更进一步,会主动通知用户其使用情况。

WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::setMemory has been called by com.foo.bar.Server (file:/tmp/foobarserver/thing.jar)
WARNING: Please consider reporting this to the maintainers of com.foo.bar.Server
WARNING: sun.misc.Unsafe::setMemory will be removed in a future release

JEP 486:永久禁用安全管理器

安全管理员(Security Manager)很少用于保护服务器端代码,且其维护成本高昂。该功能在Java 17中已被弃用。由于其采用率低,且大多数框架和工具已放弃对其支持,Java 24中已永久禁用了Security Manager。

预览与孵化器

预览版和孵化器涵盖了正在开发中的功能,这些功能仍处于测试阶段,尚未准备好用于生产环境。它们被发布出来,以便用户可以启用这些功能并提供反馈。

要启用这些功能,您需要在编译和运行代码时添加 --enable-preview 选项。

  1. 编译代码:

javac --release 24 --enable-preview Main.java

然后使用以下命令运行它:

java --enable-preview Main

2. 直接运行源代码:

java --enable-preview Main.java

3. 当使用 jshell 时:

jshell --enable-preview

JEP 478:密钥派生函数API(预览版)

JEP 478 引入了一个用于密钥派生函数(KDF)的API。这些加密算法能够从一个秘密密钥和其他数据中派生出额外的密钥。

// Create a KDF object for the specified algorithm
KDF hkdf = KDF.getInstance("HKDF-SHA256");

// Create an ExtractExpand parameter specification
AlgorithmParameterSpec params =
    HKDFParameterSpec.ofExtract()
                     .addIKM(initialKeyMaterial)
                     .addSalt(salt).thenExpand(info, 32);

// Derive a 32-byte AES key
SecretKey key = hkdf.deriveKey("AES", params);

// Additional deriveKey calls can be made with the same KDF object

此功能支持的未来工作:

  • 重构TLS 1.3:TLS 1.3协议实现可以从这个新的KDF API中受益,以改进密钥管理。然而,目前尚无计划将此API集成到TLS的早期版本中。
  • Argon2实现:Java的未来版本还可能包含Argon2派生算法的实现,该算法以抵御暴力攻击和有效保护密码而闻名。

JEP 499:结构化并发(第四版预览)

结构化并发是一种借助虚拟线程实现的现代方法,它能够将任务拆分为子任务,并更高效地并行运行。在Java 19和20的孵化期后,结构化并发在Java 21中作为预览版(通过JEP 453)被引入。

与之前的版本(Java 22 和 23)一样,为了收集更多用户反馈,Java 24 中再次提供了此功能,且未进行重大修改。

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 487:作用域值(第四版预览)

作用域值允许您将一个或多个值传递给不同的方法,而无需显式声明它们为参数,也无需在每次连续调用时都传递它们。这种方法简化了上下文数据的管理,例如登录用户或会话。

此功能在Java 24中第四次进行预览,以收集用户的更多反馈。

以下示例说明了API如何将登录用户定义为作用域值:

public class Api {
  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(() -> apiWebService.processRequest(request));
    . . .
  }
}

JEP 489:Vector API(第九个孵化器)

该特性的目标是引入一个用于表达向量计算的API,该API能够在运行时在支持的CPU架构上可靠地编译为最优指令。

向量运算提供了高度的并行性,能够在单个CPU周期内处理多个操作,从而显著提升性能。例如,对于两个分别包含八个整数序列的向量,一条硬件指令即可同时执行八个加法操作,将两个向量的元素相加,而非仅仅一个。

此功能目前处于孵化阶段,这意味着它仍在开发中,且每个版本之间都会经历重大演变。

Java 24:JVM内部工作机制的变化

这些改进主要旨在优化JVM性能,而不会引入任何新功能或改变开发实践。

垃圾收集器

垃圾收集器负责JVM中的内存管理。堆内存被分为两部分(或称几代):新生区(或称年轻空间/年轻代)和老空间(或称老代)。

大多数对象都是在Eden空间中创建的,随着它们在垃圾收集器周期中的存活,逐渐被移至老年代。

此外,JVM提供了多种垃圾收集器(GC)类型(G1、ZGC、Shenandoah、Serial、Parallel等),每种类型都有其特定的功能和优势。

JEP 404:分代式 Shenandoah(实验性)

迄今为止,Shenandoah 垃圾收集器一直使用单一内存区域。现在,此功能使其能够按照上述的分代原则进行操作。

它处于实验阶段,意味着目前正在测试中,必须通过以下选项明确启用:-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational

JEP 475:G1的延迟屏障扩展

随着基于云的Java部署日益普及,人们越来越重视降低JVM的整体负载。

即时编译(JIT)是加速Java应用程序的关键技术,但它会在处理时间和内存使用方面带来显著负担。

此功能的主要目标是减少C2优化器的运行时间,尤其是在与G1垃圾收集器一起使用时。

这一增强功能在优化性能的同时,最大限度地减少了系统资源的影响。

JEP 490:ZGC:移除非分代模式

此特性从Z垃圾收集器(ZGC)中移除了非分代模式,保留分代模式作为默认设置。主要目标是降低管理与两种独立模式相关的维护成本。

运行时 在JVM运行时方面,工作的主要重点是提高性能和优化内存使用。

JEP 450:紧凑对象头(实验性)

该特性旨在减小Java对象头的大小。目前,每个Java对象都包含类、锁、哈希码等信息,这些信息存储在96至128位的对象头中。本实验旨在将这些对象头的大小减小到64位,以优化JVM的内存占用。

这是一个实验性功能,意味着它仍处于测试阶段。要启用它,在运行JVM时必须使用以下选项:-XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders

JEP 483:提前类加载与链接

该特性的目标是确保应用程序的类在Java HotSpot虚拟机启动后立即可用、加载和链接,从而缩短启动时间。通过在运行时之前执行这些操作,而不是在运行时执行,可以减少Java应用程序的启动时间。

import java.util.*;
import java.util.stream.*;

public class HelloStream {

    public static void main(String ... args) {
        var words = List.of("hello", "fuzzy", "world");
        var greeting = words.stream()
            .filter(w -> !w.contains("z"))
            .collect(Collectors.joining(", "));
        System.out.println(greeting);  // hello, world
    }

}

例如,这里有一个使用Stream API的简单程序。尽管它很简洁,但需要你阅读、分析、加载和链接近600个JDK类。

此程序在JDK 23上运行时间为0.031秒。然而,在创建AOT缓存后,它在JDK 24上的运行时间应缩短至0.018秒,性能提升42%。

JEP 491:在不锁定的情况下同步虚拟线程

此功能旨在:

使现有的Java库能够无需进行重大修改即可正确适应虚拟线程,特别是通过避免使用同步方法和指令;改进诊断功能,以识别虚拟线程无法释放物理线程(阻塞)的情况,从而确保实现最优的资源管理。

JEP 493的其他改进:无需JMOD即可链接运行时镜像

该特性的目标是通过使用jlink工具创建自定义运行时镜像,而不使用JDK的JMOD文件,从而将JDK的大小减少约25%。

在创建JDK时,必须启用此功能,默认情况下该功能不会启用,且部分JDK供应商可能会选择不启用它。

JEP 479:移除Windows 32位x86端口

这标志着对Windows 32位x86端口的源代码和支持的移除,该端口自Java 21起已被弃用。

JEP 501:弃用32位x86移植以待移除

32位x86移植,尤其是针对Linux的移植,现已被视为过时,并将在未来版本中停止支持。这标志着JDK对此架构的支持正式结束。

Java 24是Java 25到来之前的最后一个版本,Java 25是下一个长期支持(LTS)版本。这是一个过渡版本,旨在完善将集成到LTS版本中的功能。

此版本标志着JDK中语言和API的稳定。显然,现在的重点是优化JVM性能和减少内存占用。

时间会证明这些发展是否会结出硕果,并继续改善Java生态系统。

原文地址: https://www.sqli.com/int-en/insights/java-24

  
 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/3044.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册