Java19于2022年9月20日正式发布。Java19直到2023年3月才成为长期支持版本。它将被JDK20取代。本次更新共带来7项新特性。?bin./java-versionopenjdkversion"19"2022-09-20OpenJDKRuntimeEnvironment(build19+36-2238)OpenJDK64-BitServerVM(build19+36-2238,mixedmode,sharing)OpenJDKJava19下载:https://jdk.java.net/19/OpenJDKJava19文档:https://openjdk.java.net/projects/jdk/19/Java19带来了7个新特性:JEP描述了405记录模式匹配(预览版)425虚拟线程(preview)427Switchpatternmatching(三个预览)422Linux/RISC-VPort426VectorAPI(四个incubation)424Externalfunction&memoryAPI(Preview)428StructuredConcurrency(Incubator)Java19新特性介绍是Java新特性系列文章的一部分.系列详情可以浏览:https://www.wdbyte.com/java-feature/JEP405:Recordpatternmatching(preview)record是一个全新的类型,它本质上是一个final类,所有属性都是final修改后,会自动编译publicgethashcode、equals、toString等方法,减少代码编写量。Record在Java14提出,Java15预览,Java16正式发布。示例:写一个Dog记录类,定义name和age属性。包com.wdbyte;publicrecordDog(Stringname,Integerage){}记录的使用。packagecom.wdbyte;publicclassJava14Record{publicstaticvoidmain(String[]args){Dogdog1=newDog("ShepherdDog",1);Dogdog2=newDog("田园犬",2);Dogdog3=newDog("哈士奇",3);System.out.println(dog1);System.out.println(dog2);System.out.println(dog3);}}输出结果:Dog[name=ShepherdDog,age=1]Dog[name=PastoralDog,age=2]Dog[name=Husky,age=3]在Java19中,给Record带来了增强的模式匹配,并且使用instanceof后可以进行类型转换。publicclassRecordTest{publicstaticvoidmain(String[]args){Objectdog1=newDog("Sheepdog",1);if(dog1instanceofDogdogTemp){System.out.println(dogTemp.name());}}}recordDog(Stringname,Integerage){}在使用instanceof时甚至可以直接获取Record中的变量引用。publicclassRecordTest2{publicstaticvoidmain(String[]args){Objectdog1=newDog("Sheepdog",1);if(dog1instanceofDog(Stringname,Integerage)){System.out.println(name+":"+age);}}}recordDog(Stringname,Integerage){}扩展:Java14instanceof类型推断Java16Record引入JEP425:虚拟线程(预览版)是一个有用的新特性,从Java19开始逐步引入虚拟线程。虚拟线程是轻量级线程,可以显着减少代码编写,提高可维护性,提高系统吞吐量。引入的原因一直是Thread一直是Java并发编程中非常重要的一部分。线程是Java中的并发单元。每个Thread线程都提供了一个栈来存放局部变量和方法调用,以及线程上下文等相关信息。但问题是线程和进程一样,是一种昂贵的资源。JDK将Thread线程作为操作系统线程的包装器来实现,这意味着成本高且数量有限。因此,我们会使用线程池来管理线程,限制线程的数量。例如,常用的Tomcat会对每个请求使用单独的线程进行请求处理,并限制处理请求的线程数,防止线程过多而崩溃;很可能在CPU或网络连接耗尽之前,线程数就已经耗尽,从而限制了Web服务的吞吐量。看到这里,你可能想说可以放弃请求和线程一一对应的方式,使用异步编程来解决这个问题,将请求处理分割成顺序管道,通过一组蜜蜂。可以使用有限数量的线程来处理超过线程数量的请求。这当然是可以的,但是随之而来的问题是:需要额外学习异步编程。代码复杂度的增加相当于放弃了语言基本的顺序组合操作。堆栈上下文信息变得难以跟踪。调试困难。它与Java平台本身的编程风格相冲突。Java的并发单元是Thread,此时是异步管道。虚拟线程基于以上原因,Java19引入了虚拟线程,它在用户体验上与Thread没有区别,并且兼容之前的API。但是相比之下,虚拟线程占用的资源非常少,优化了硬件的使用效率,所以非常好用,不需要池化。下面是一个例子。创建100,000个线程,然后休眠1秒。最后,打印需要时间。如果是传统的Thread线程方式,资源非常紧张;如果是线程池方式,肯定有一些线程在等待线程Release;但是使用虚拟线程,它可以立即完成。导入java.util.concurrent.Executors;导入java.util.stream.IntStream;公共类ThreadTest{publicstaticvoidmain(String[]args){longstart=System.currentTimeMillis();try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){IntStream.range(0,100_000).forEach(i->{executor.submit(()->{Thread.sleep(1000);returni;});});}System.out.println("耗时:"+(System.currentTimeMillis()-start)+"ms");}}执行后发现1.3秒就执行完毕,速度惊人。?bin./java--enable-preview--source19ThreadTest.java注意:ThreadTest.java使用JavaSE19的预览功能。注意:使用-Xlint:preview重新编译以获取详细信息。耗时:1309ms?bin注意:虚拟线程只是增加程序的吞吐量,并不能提高程序的处理速度。JEP427:switchpatternmatching(三预览)Switch模式匹配在Java17中已经引入,在Java18中预览了两次,现在在Java19中预览了三次,Java18引入的特性和新特性-Switch同样,改进后的Switch模式匹配可以让代码更简洁,逻辑更清晰。以下是一些使用示例以供比较。这里有几个例子:staticStringformatter(Objecto){Stringformatted="unknown";if(oinstanceofIntegeri){formatted=String.format("int%d",i);}elseif(oinstanceofLongl){formatted=String.format("long%d",l);}elseif(oinstanceofDoubled){formatted=String.format("double%f",d);}elseif(oinstanceofStrings){formatted=String.format("String%s",s);}returnformatted;}在Java17之后,可以通过这样写来改进:staticStringformatterPatternSwitch(Objecto){returnswitch(o){caseIntegeri->String.format("int%d",i);caseLongl->String.format("long%d",l);caseDoubled->String.format("double%f",d);caseStrings->String.format("String%s",s);默认->o.toString();};}switch可以结合null来判断:staticvoidtestFooBar(Strings){switch(s){casenull->System.out.println("Oops");case"Foo","Bar"->System.out.println("Great");默认->System.out.println("确定");}}case可以添加复杂的表达式:staticvoidtestTriangle(Shapes){switch(s){caseTrianglet&&(t.calculateArea()>100)->System.out.println("大三角形");default->System.out.println("一个形状,可能是一个小三角形");}}case可用于类型判断:sealedinterfaceSpermitsA,B,C{}finalclassAimplementsS{}finalclassBimplementsS{}recordC(inti)implementsS{}//隐式finalstaticinttestSealedExhaustive(Ss){returnswitch(s){caseAa->1;案例Bb->2;案例Cc->3;};}Extensions:JEP406:TypeMatchingforSwitch(Preview)JEP422:Linux/RISC-VPortRISC-V是一个自由开源的RISC指令集架构(ISA),实际上RISC-V是一系列相关的ISA,现在Java19开始支持它JEP424:ExternalFunctions&MemoryAPI(Preview)此功能引入的API允许Java开发人员与JVM外部的代码和数据交互,通过调用外部函数(JVM外部)和安全访问外部内存(非JVM管理),允许Java程序调用本机库并处理本机数据,而不会像JNI那样存在许多安全风险。这并不是一个新特性,它是从Java14开始引入的,这次在性能、通用性、安全性和易用性方面进行了优化。历史Java14JEP370引入了外部内存访问API(孵化器)。Java15JEP383引入了外部内存访问API(第二个孵化器)。Java16JEP389引入了外部链接器API(孵化器)。Java16JEP393引入了外部内存访问API(第三孵化器)。Java17JEP412引入了外部函数和内存API(孵化器)。Java18JEP419引入了外部函数和内存API(二级孵化器)。其他更新JEP426:VectorAPI(第四次孵化)通过将在运行时可靠地编译为支持的CPU架构上的矢量指令的矢量计算表示为等效标量计算,实现了卓越的性能。这个特性已经第四次孵化了,之前在Java16~Java18中有介绍,这里不再赘述。JEP428:结构化并发(孵化)通过简化多线程编程并将在不同线程中运行的多个任务视为一个工作单元来简化错误处理和取消,提高可靠性并增强可观察性。
