异常参数和 lambda 参数
发布时间:2025-06-24 20:59:55 作者:北方职教升学中心 阅读量:902
在JEP 447之前,这样的逻辑需要使用一个辅助方法来完成,而这个特性使得可以直接在构造函数中包含这种验证逻辑,使得代码更加清晰和直观。
发布时间:2025-06-24 20:59:55 作者:北方职教升学中心 阅读量:902
在JEP 447之前,这样的逻辑需要使用一个辅助方法来完成,而这个特性使得可以直接在构造函数中包含这种验证逻辑,使得代码更加清晰和直观。
javac --release 22--enable-preview YourProgram.javajava --enable-preview YourProgram
JEP 464 的作用域值提供了一种新的、
示例代码
:
以下是一个使用 JEP 463 功能的简单示例,展示了如何编写一个没有显式类声明的 main 方法:
// 这是一个简单的 Hello, World! 程序,没有显式的类声明
voidmain(){System.out.println("Hello, World!");}
如果你想要在同一个文件中包含多个方法,可以这样做:
// 使用隐式声明的类,包含多个方法Stringgreeting(){return"Hello, World!";}voidmain(){System.out.println(greeting());}
或者,你可以使用一个字段:
// 使用隐式声明的类,包含一个字段Stringgreeting ="Hello, World!";voidmain(){System.out.println(greeting);}
要尝试这些示例,你需要在 JDK 22 中启用预览功能,如下所示:
javac --release 22--enable-preview Main.javajava --enable-preview Main
或者,如果你使用的是源代码启动器:
java --source 22--enable-preview Main.java
JEP 463 的目标是提供一个平滑的学习曲线,使得学生和新程序员能够以简洁的方式编写基本程序,并随着他们技能的提升,逐步扩展到使用 Java 的更高级特性。用户驱动的导航、
收集器与收集器的区别:虽然收集器类似于收集器,但它们在处理每个元素时使用集成器(而不是双消费者),并且在完成器中使用双消费者(而不是函数),因为它们需要处理下游对象,并且不能返回结果。
该版本的特性和计划通过 JEP(JDK 增强提案)流程提出和跟踪,根据 JEP 2.0 提案进行了修订。
JEP 459 引入了字符串模板(String Templates)作为 Java 语言的第二个预览功能,旨在提供一种更清晰、这样,即使在频繁使用 JNI 的应用程序中,也能保持更好的响应性和吞吐量。这个特性不会引入 Java 语言的另一个初学者方言,也不会引入一个单独的初学者工具链。
启动类选择:启动器会选择具有标准main方法的类作为启动类。异常参数和 lambda 参数。
以下是 JDK 22 中的一些主要特性:
源文件模式:通过传递单个.java文件的名称来触发启动器的源文件模式。
核心要点
:
示例代码
:
以下是一个使用 StructuredTaskScope 的简单示例,它演示了如何在服务器应用程序中处理两个并发的子任务:
importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.StructuredTaskScope;importjava.util.concurrent.TimeUnit;importjava.util.stream.Stream;publicclassStructuredConcurrencyExample{publicstaticvoidmain(String[]args){try(StructuredTaskScope<String>scope =newStructuredTaskScope<>()){// 分叉两个子任务Supplier<String>task1 =scope.fork(()->findUser());Supplier<String>task2 =scope.fork(()->fetchOrder());// 等待所有子任务完成或被取消scope.join();// 检查是否有子任务失败,并抛出异常scope.throwIfFailed();// 处理子任务的结果Stringuser =task1.get();Stringorder =task2.get();System.out.println("User: "+user +", Order: "+order);}catch(Exceptione){e.printStackTrace();}}privatestaticStringfindUser(){// 模拟用户查找逻辑return"User123";}privatestaticStringfetchOrder(){// 模拟订单获取逻辑return"Order456";}}
在这个示例中,我们创建了一个 StructuredTaskScope 实例,并在其中分叉了两个子任务 task1 和 task2。
核心要点
:
启动时编译:启动器在运行时编译源文件,可能会根据需要逐步编译或延迟编译。
非目标:不旨在增强 HotSpot 中现有的自动向量化算法;不支持除 x64 和 AArch64 之外的 CPU 架构的向量指令;不支持 C1 编译器;不保证支持严格浮点计算。
JEP 461 引入了流收集器(Stream Gatherers)作为 Java 流(Stream)API 的预览特性,允许开发者自定义中间操作,从而增强了流管道的灵活性和表达能力。这是继 JEP 445 之后的第二轮预览功能,提供了一些重要的变化,并因此更新了标题。这意味着将 Vector API 中的当前基于值的类更改为值类,以便程序可以使用值对象,即缺乏对象身份的类实例。
示例代码
:
publicclassValidatedBigIntegerextendsBigInteger{// 构造函数中使用预览特性,在调用超类构造函数之前执行验证publicValidatedBigInteger(longvalue){if(value <=0){// 执行验证逻辑thrownewIllegalArgumentException("非正整数");}super(value);// 调用超类构造函数}}
在这个示例中,ValidatedBigInteger 类在创建实例之前先验证了传入的 value 是否大于0。
优雅降级:如果向量计算不能完全表达为向量指令序列,例如因为架构不支持某些必需的指令,Vector API 的实现应该能够优雅降级并继续运行。作用域值旨在解决线程局部变量(ThreadLocal)的一些设计缺陷,提供更简单、这可能涉及在无法有效编译为向量指令的向量计算时发出警告。
核心要点
:
国际化和本地化:字符串模板可以简化国际化和本地化的过程,通过模板处理器来处理不同的语言和格式。一对多、这个过程中,我们不需要使用JNI,而是直接通过Java代码来完成对本地函数的调用和内存的管理。
内置收集器:java.util.stream.Gatherers 类引入了几个内置收集器,如 fold、此外,由于这是一个预览API,它可能在未来的Java版本中会有所改变。
示例代码
:
// 使用 STR 模板处理器进行基本的字符串插值Stringname ="Joan";Stringinfo =STR.Myname is \{name};System.out.println(info);// 输出:My name is Joan// 使用 FMT 模板处理器进行格式化doublevalue =123.456;Stringformatted =FMT."The value is %6.2f";System.out.println(formatted);// 输出:The value is 123.46// 多行模板示例Stringhtml =STR.""" <html> <head> <title>My Web Page</title> </head> <body> <p>Hello, world!</p> </body> </html>""";System.out.println(html);// 自定义模板处理器示例varINTER=StringTemplate.Processor.of((StringTemplatest)->{StringBuildersb =newStringBuilder();Iterator<String>fragIter =st.fragments().iterator();for(Objectvalue :st.values()){sb.append(fragIter.next());sb.append(value);}sb.append(fragIter.next());returnsb.toString();});Stringresult =INTER."\{value}";System.out.println(result);// 输出:{value}
这些示例展示了如何使用内置的 STR 和 FMT 模板处理器,以及如何创建自定义的模板处理器。
请注意,为了使用作用域值,你需要启用预览功能。
JEP 423 通过在 G1 垃圾回收器中实现区域固定,允许在 JNI 关键区域期间继续进行垃圾回收,从而减少了延迟。在 processRequest 方法中,我们通过调用 ScopedValue.where 方法来绑定用户信息,并在一个特定的作用域内执行代码。
示例代码
:
假设我们有两个源文件Prog.java和Helper.java,它们位于同一个目录中:
// Prog.javaclassProg{publicstaticvoidmain(String[]args){Helper.run();}}// Helper.javaclassHelper{staticvoidrun(){System.out.println("Hello, World!");}}
要运行这个程序,只需在命令行中使用java命令:
$ java Prog.java
启动器会自动找到Helper.java文件,编译它,然后执行Prog类的main方法。emergent transformation、这些函数共同作用于处理流元素并维护状态。未命名变量和模式的使用消除了对未使用变量的命名需求,使得代码更加简洁和直观。
核心要点
:
核心要点
:多文件源代码程序支持:开发者可以使用java命令直接运行由多个.java文件组成的程序,而不需要先将它们编译成.class文件。
示例代码
:以下是一个使用FFM API调用C库中的strlen函数来计算字符串长度的示例。一个集成器、构建器(用于创建类文件的组件)和转换(用于修改类文件的函数)。
示例代码
:由于 JEP 423 主要是关于垃圾回收器的内部工作机制,它并不直接提供新的API或者对开发者可见的行为改变,因此没有直接的示例代码。以下是其核心要点和示例代码:
核心要点
:
组合收集器:收集器可以使用 andThen 方法进行组合,通过结合更简单的收集器来创建复杂的收集器。如果提供了额外的文件名,它们将成为主方法的参数。
示例代码
:
// 使用未命名变量的增强 for 循环staticintcount(Iterable<Order>orders){inttotal =0;for(Order_ :orders){// 使用未命名变量total++;}returntotal;}// 在 while 循环中使用未命名变量Queue<Integer>q =...;while(q.size()>=3){varx =q.remove();var_ =q.remove();// 使用未命名变量var_ =q.remove();// 使用未命名变量...newPoint(x,0)...// 只使用 x}// 使用未命名变量的 catch 块Strings =...;try{inti =Integer.parseInt(s);...i ...}catch(NumberFormatException_ ){// 使用未命名变量System.out.println("Bad number: "+s);}// 在 try-with-resources 语句中使用未命名变量try(var_ =ScopedContext.acquire()){// 使用未命名变量...// 不使用 acquired resource}// 使用未命名变量的 lambda 表达式...stream.collect(Collectors.toMap(String::toUpperCase,_ ->"NODATA"))// 使用未命名变量// 使用未命名模式变量的 switch 语句switch(ball){caseRedBall_ ->process(ball);caseBlueBall_ ->process(ball);caseGreenBall_ ->stopProcessing();}// 使用未命名模式的 instanceof 检查if(r instanceofColoredPoint(Point(intx,_),_)){// 未使用的组件使用未命名模式...x ...}
这些示例展示了如何在不同场景下使用未命名变量和未命名模式,从而简化代码并提高可读性。
核心要点
:
自定义中间操作:定义自定义操作的能力,可以按照一对一、
模板处理器:用于处理字符串模板并生成结果。统一的流式和实体化视图、API 应该能够表达与向量大小(每个向量中的通道数)无关的通用计算,从而在支持不同向量大小的硬件上实现可移植性。注解处理在源文件模式下被禁用。多对一或多对多的方式转换流中的元素。如果在数组的末尾有剩余的元素,我们使用一个普通的标量循环来处理这些元素。构建器和转换: API定义了元素(类文件的不可变描述)、这个类总是 final 的,并且只能继承 Object 类。在使用之前,需要确保你的开发环境已经启用了预览特性。
收集器接口:收集器由四个函数定义:一个可选的初始化器、
API 支持:提供了 StringTemplate 接口和相关的 API,允许开发者创建自定义的模板处理器。
核心要点
:JEP 454引入了Foreign Function & Memory API (FFM API),它允许Java程序高效且安全地调用本地(外部)函数和访问外部内存,从而替代了JNI的一部分功能,并提供了更好的性能和更简洁的API。生成和转换Java类文件的预览API。
安全性:字符串模板的设计确保了在将表达式的值插入到字符串中时的安全性,防止了注入攻击等安全问题。
示例代码
:
由于JEP 457是一个预览API,且涉及到的类文件操作通常不是在普通的Java应用程序中直接编写的,因此这里提供的示例代码是概念性的,用于说明如何使用API进行类文件的处理。
JEP 463 旨在改进 Java 语言,使其对初学者更加友好,允许编写不依赖于复杂语言特性的基本程序。接着,我们分配了一个内存段来存储一个字符串,并使用strlenMH方法句柄来调用strlen函数,获取并打印字符串的长度。
核心要点
:
API 目标:提供一个清晰、这提供了更大的灵活性,使得构造函数中的逻辑可以更自然地放置,而不必依赖于辅助静态方法、
2024年3月19日,Oracle 官网正式发布了 JDK22,虽然这是一个非 LTS(长期支持)版本,但 JDK22也带来了一些引人注目的新特性,V哥详细阅读了官网文档,把相关新特性总结出来,分享给大家,一睹为快。字段等classBuilder.withMethod("newMethod",MethodTypeDesc.of(void.class),methodBuilder ->{// 构建方法体methodBuilder.withCode(codeBuilder ->{// 添加字节码指令codeBuilder.aload(0).invokevirtual(MethodDesc.of(Object.class,"toString",String.class));});});});// 转换类文件byte[]transformedBytes =classFile.transform(classModel,(classBuilder,ce)->{if(ce instanceofMethodModel&&ce.methodName().stringValue().startsWith("debug")){// 忽略以"debug"开头的方法}else{// 否则保留原始元素classBuilder.with(ce);}});
请注意,这些代码片段是为了展示API的用法而设计的,并不是完整的工作代码。在实际使用中,你需要根据具体的API文档和可用的类文件操作功能来编写代码。
类路径和模块路径:程序可以从源文件启动,并且依赖于类路径或模块路径上的库。
示例代码
:
以下是使用内置收集器 windowSliding 将元素分组到滑动窗口中的示例:
importjava.util.List;importjava.util.stream.Collectors;importjava.util.stream.Stream;publicclassStreamGathererExample{publicstaticvoidmain(String[]args){Stream<String>stream =Stream.of("a","b","c","d","e");// 将元素分组到大小为2的滑动窗口中List<List<String>>slidingWindows =stream.gather(Gatherers.windowSliding(2));System.out.println(slidingWindows);// 输出:[[a, b], [c, d], [e]]}}
以下是定义一个固定大小窗口的自定义收集器的示例:
importjava.util.ArrayList;importjava.util.List;importjava.util.function.BinaryOperator;importjava.util.stream.Gatherer;publicclassAdHocGathererExample{publicstatic<T>Gatherer<T,ArrayList<T>,List<T>>fixedWindow(intwindowSize){returnGatherer.of(()->newArrayList<>(windowSize),// 初始化器(window,element,downstream)->{window.add(element);returnwindow.size()<windowSize;// 集成器},BinaryOperator.minBy((a,b)->a.size()-b.size()),// 合并器(用于并行)(window,downstream)->{if(!window.isEmpty()){downstream.push(newArrayList<>(window));}}// 完成器);}publicstaticvoidmain(String[]args){Stream<Integer>stream =Stream.of(1,2,3,4,5,6,7,8,9);// 将元素分组到大小为3的固定窗口中List<List<Integer>>fixedWindows =stream.gather(fixedWindow(3)).toList();System.out.println(fixedWindows);// 输出:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]}}
这些示例展示了新的流收集器特性的灵活性和强大能力,允许开发者创建以前使用标准流 API 无法实现的自定义流转换。这个例子展示了如何使用 Vector API 来进行向量化计算,以期在支持的硬件上获得更好的性能。
在 x64 和 AArch64 架构上的可靠运行时编译和性能:在支持的 x64 架构上,Java 运行时(特别是 HotSpot C2 编译器)应该能够将向量操作编译为高效的向量指令,如 SSE 和 AVX 支持的指令。中间构造函数或构造函数参数。这个 API 允许开发者编写能够在支持的 CPU 架构上编译为高效的硬件向量指令的向量计算代码。如果.java文件中的第一个顶级类声明了main方法,则该类为启动类。
以上是介绍 JDK22新特性的全部内容了,突然V哥想要感慨一下,技术之路,学无止境,选择 IT 技术,作个纯粹的人,享受研究技术的过程,这种带来的快感,也许只有真正热爱编程的人才能有体会。通过这个特性,垃圾回收在 JNI 关键区域期间不需要被禁用,从而提高了与本地代码交互时的性能。在 performTask 方法中,我们可以在另一个线程中安全地读取相同的用户信息,因为作用域值被子线程继承。
示例代码
:
以下是一个简单的示例,展示了如何使用 Vector API 来执行浮点数数组的向量计算:
importjdk.incubator.vector.FloatVector;importjdk.incubator.vector.VectorSpecies;publicclassVectorExample{staticfinalVectorSpecies<Float>SPECIES=FloatVector.SPECIES_PREFERRED;publicstaticvoidmain(String[]args){float[]arrayA ={/* ... 初始化数组 ... */};float[]arrayB ={/* ... 初始化数组 ... */};float[]resultArray =newfloat[arrayA.length];inti =0;intupperBound =SPECIES.loopBound(arrayA.length);for(;i <upperBound;i +=SPECIES.length()){FloatVectorva =FloatVector.fromArray(SPECIES,arrayA,i);FloatVectorvb =FloatVector.fromArray(SPECIES,arrayB,i);FloatVectorvc =va.mul(va).add(vb.mul(vb)).neg();vc.intoArray(resultArray,i);}for(;i <arrayA.length;i++){resultArray[i]=(arrayA[i]*arrayA[i]+arrayB[i]*arrayB[i])*-1.0f;}}}
在这个示例中,我们首先获取一个最优的向量种类(SPECIES),然后在一个循环中使用向量操作来计算两个数组的元素的特定数学表达式,并将结果存储到另一个数组中。
// 获取链接器和符号查找器Linkerlinker =Linker.nativeLinker();SymbolLookupstdlib =linker.defaultLookup();// 找到C库中的strlen函数MemorySegmentstrlenSymbol =stdlib.find("strlen").get();// 创建一个下调用方法句柄,它将strlen函数作为本地方法调用MethodHandlestrlenMH =linker.downcallHandle(strlenSymbol,FunctionDescriptor.of(JAVA_LONG,ADDRESS));// 分配一个内存段来存储一个字符串MemorySegmentstrSegment =Arena.allocateFrom("Hello, World!");// 调用strlen函数来获取字符串的长度longstringLength =(long)strlenMH.invokeExact(strSegment);// 输出字符串长度System.out.println("String length: "+stringLength);
在这个示例中,我们首先通过Linker获取到C标准库中的strlen函数的内存段引用,然后创建一个方法句柄来调用这个函数。
示例代码
:
以下是一个使用 JEP 464 的作用域值的示例:
importjava.util.concurrent.ScopedValue;// 定义一个作用域值,用于存储用户信息privatestaticfinalScopedValue<UserInfo>currentUser =ScopedValue.newInstance();// 模拟用户信息的创建UserInfocreateUserInfo(Stringusername){// 创建并返回用户信息对象returnnewUserInfo(username);}// 模拟一个需要用户信息的方法voidprocessRequest(Stringusername){// 绑定当前请求的用户信息ScopedValue.where(currentUser,createUserInfo(username)).run(()->{// 在这个作用域内,可以直接获取当前用户信息UserInfouserInfo =currentUser.get();// 处理请求...});}// 另一个方法,可能在另一个线程中执行voidperformTask(){// 在这个线程中,我们可以安全地读取用户信息UserInfouserInfo =currentUser.get();// 执行任务...}
在这个示例中,我们创建了一个名为 currentUser 的 ScopedValue 对象,用于存储当前用户的信息。更安全且性能更优的数据共享方式。
反射和注解处理:通过反射访问的类和直接访问的类以相同的方式加载。
内存中的编译:编译的类存储在内存缓存中,而不是写入磁盘。例如,包名为pkg的类应该放在foo/bar目录下。
这是官网对 JDK22版本新特性的概要截图:
翻译一下:
::: block-1
JDK 22 是 Java SE 平台的第 22 个版本的参考实现,它遵循 Java 社区进程中的 JSR 397 规范。Oracle 提供了符合 GPL 协议的生产就绪二进制文件,而其他供应商的二进制文件也将很快跟进。
限制:源文件程序不能跨越多个模块,这可能是未来的改进点。
JEP 462 旨在通过引入结构化并发的 API 来简化并发编程。在没有 JEP 423 之前,每次进入 JNI 关键区域,G1 垃圾回收器都会暂停,等待关键区域结束。本次发布使用 JDK 发布流程(JEP 3)进行。细节隐藏以及利用Java语言的特性。树状结构表示、
publicclassNativeObject{// 假设这是一个通过 JNI 创建的本地对象privatelongnativeObject;// 使用 JNI 创建本地对象publicNativeObject(){// 调用本地方法创建对象,这将进入 JNI 关键区域nativeObject =createNativeObject();}// 释放本地对象,也需要通过 JNIpublicvoidrelease(){// 调用本地方法释放对象,这同样是一个 JNI 关键区域releaseNativeObject(nativeObject);nativeObject =0;// 清除引用}// 调用本地方法创建本地对象的静态方法privatenativelongcreateNativeObject();// 调用本地方法释放本地对象的静态方法privatenativevoidreleaseNativeObject(longobject);}publicclassMain{publicstaticvoidmain(String[]args){NativeObjectobj =null;try{obj =newNativeObject();// 在这里可以对 obj 进行操作}finally{if(obj !=null){obj.release();// 释放本地对象资源}}}}
在这个示例中,NativeObject 类使用 JNI 创建和释放本地资源。
JEP 464 引入了作用域值(Scoped Values),这是一种新的机制,用于在同一个线程及其子线程之间共享不可变数据。
目录结构:源文件需要按照包结构组织在目录中。mapConcurrent、懒惰性、
并行执行:当提供了合并器函数时,收集器可以支持并行执行,允许在并行流中高效处理。windowFixed 和 windowSliding。对于 ARM AArch64 架构,C2 也应该将向量操作编译为 NEON 和 SVE 支持的向量指令。STR 和 FMT 是 Java 平台提供的内置模板处理器,分别用于基本的字符串插值和格式化。
平台无关性:API 应该是 CPU 架构无关的,支持在多种支持向量指令的架构上实现。
JEP 458的目标是增强Java应用程序启动器(java launcher),使其能够运行由多个Java源代码文件组成的程序。
JEP 460 旨在将 Vector API 作为第七个孵化版引入 JDK 22。如果任何子任务失败,throwIfFailed 方法将抛出异常,允许我们处理错误。
核心要点
:
字符串模板:一种新的表达式,允许在字符串中嵌入表达式,并在运行时替换这些表达式。
支持无限流:自定义中间操作可以处理无限大小的流,并且有可能将它们转换为有限的流,通过短路机制实现。不过,我们可以展示一个使用 JNI 的场景,来说明在没有 JEP 423 之前可能遇到的问题,以及 JEP 423 如何改善这种情况。如果 value 不大于0,它将抛出一个 IllegalArgumentException。
关于 JDK 22 的发布计划:
下面跟V哥一起来针对每个新特性做详细的解释:
核心要点
:JEP 423 引入了 G1 垃圾回收器中的区域固定(Region Pinning)功能,这是为了减少 Java 原生接口(JNI)关键区域期间的延迟。
多行模板:字符串模板可以跨越多行,类似于文本块(text block)的语法。
核心要点
:JEP 447 引入了在构造函数中超类构造函数调用之前的语句的预览特性。
// 解析类文件ClassFileclassFile =ClassFile.of();ClassModelclassModel =classFile.parse(bytes);// 生成类文件byte[]newBytes =classFile.build(classModel.thisClass().asSymbol(),classBuilder ->{// 使用构建器添加方法、
与 Project Valhalla 保持一致:Vector API 的长期目标是利用 Project Valhalla 对 Java 对象模型的增强。