您的位置:首页 > 汽车 > 时评 > Java16的主要新特性总结

Java16的主要新特性总结

2024/11/18 2:37:11 来源:https://blog.csdn.net/donggongai/article/details/140376200  浏览:    关键词:Java16的主要新特性总结

目录

概述

变动说明

重要变更和信息

下载地址

Java16新特性总结

1、JEP 395:Record类(正式特性)

功能进化

一个示例类

紧凑型构造函数

使用限制

与record相关的API

2、JEP 394:模式匹配的 instanceof(正式特性)

功能进化

作用域

与运算符结合

3、JEP 397:密封的类和接口(第二次预览)

功能进化

密封类

什么是密封类

示例代码

4、细微改动

(1)增加Stream.toList()方法(JDK-8180352 )

Stream.toList()和stream.collect(Collectors.toList())的区别

(2)java.time包的格式化支持一天中的数据段(JDK-8180352 )

(3)HttpClient的默认实现返回可取消的Future对象(JDK-8245462)

(4)修正Path.of或Paths.get的第一个参数为null时不会抛出空指针异常的问题(JDK-8254876)

5、JEP 338:向量 API(孵化器特性)

6、JEP 347:启用 C++14 语言特性

7、JEP 357:将JDK的源代码库从Mercurial迁移到Git

8、JEP 369:将JDK的源代码库托管到GitHub

9、JEP 376:ZGC 并发线程处理

功能进化

10、JEP 380:Unix-Domain 套接字通道

11、JEP 386:AlpineLinux 移植

12、JEP 387:弹性元空间

13、JEP 388:Windows/AArch64 移植

14、JEP 389:外部函数与内存 API(孵化特性)

功能进化

15、JEP 390:对基于值的类发出警告

16、JEP 392:打包工具(正式特性)

功能进化

安装.Net Framework 3

安装WiX

17、JEP 393:外部存储器访问 API(第三次孵化)

功能进化

18、JEP 396:默认强封装 JDK 内部元素

19、移除的APIs、工具、容器

Oracle JDK和OpenJDK之间的差异


概述

JDK 16 于 2021 年 3 月 16 日正式发布。

JEP(Java Enhancement Proposal)Java增强提案

CSR(Compatibility & Specification Review) 兼容性和规范审查

变动说明

官网:

Java Platform, Standard Edition Java Language Updates, Release 16

JDK 16 Release Notes

JDK 16

更多参考:

JDK 16 Documentation - Home 更多版本:Java Platform, Standard Edition Documentation - Releases

Java Platform, Standard Edition Oracle JDK Migration Guide, Release 16

重要变更和信息

JDK 16 包含 17 个 新特性 ,分别为:

  • JEP 338: Vector API (Incubator) 向量 API(孵化特性)

  • JEP 347: Enable C++14 Language Features 启用 C++14 语言特性

  • JEP 357: Migrate from Mercurial to Git 将JDK的源代码库从Mercurial迁移到Git

  • JEP 369: Migrate to GitHub 将JDK的源代码库托管到GitHub

  • JEP 376: ZGC: Concurrent Thread-Stack Processing ZGC 并发线程处理

  • JEP 380: Unix-Domain Socket Channels Unix-Domain 套接字通道

  • JEP 386: Alpine Linux Port AlpineLinux 移植

  • JEP 387: Elastic Metaspace 弹性元空间

  • JEP 388: Windows/AArch64 Port Windows/AArch64 移植

  • JEP 389: Foreign Linker API (Incubator) 外部函数与内存 API(孵化特性)

  • JEP 390: Warnings for Value-Based Classes 对基于值的类发出警告

  • JEP 392: Packaging Tool 打包工具(正式版)

  • JEP 393: Foreign-Memory Access API (Third Incubator) 外部存储器访问 API(第三次孵化)

  • JEP 394: Pattern Matching for instanceof instanceof的模式匹配 (正式特性)

  • JEP 395: Records Record类(正式特性)

  • JEP 396: Strongly Encapsulate JDK Internals by Default 默认强封装 JDK 内部元素

  • JEP 397: Sealed Classes (Second Preview) 密封类(第二次预览)

而其中与开发过程中直接相关的特性主要包括:JEP 394(instanceof的模式匹配 (正式特性))、JEP 395(Record类)、JEP 397(密封类(第二次预览))等。

下载地址

您可以从这个链接下载生产就绪的OpenJDK版本。文件为压缩包,解压并设置环境变量就可以使用。

当然你也可以从这个链接下载Oracle JDK版本(但是需要注意商用限制),更多版本下载。

Java16新特性总结

1、JEP 395:Record类(正式特性)

JEP 395 (tools/javac

功能进化
Java版本特性类型JEP特性
Java 14预览特性JEP 359引入Record类作为预览特性
Java 15预览特性JEP 384修正及优化,语法上同上一版没有区别
Java 16正式特性JEP 395成为正式特性

JDK14中,引入了一个新类java.lang.Record。这是一种新的类型声明。Records 允许我们以一种简洁的方式定义一个类,我们只需要指定其数据内容。对于每个Record类,Java 都会自动地为其成员变量生成 equals(), hashCode(), toString() 方法,以及所有字段的访问器方法(getter),为什么没有 setter方法呢?因为Record的实例是不可变的,它所有的字段都是 final 的,这就意味着一旦构造了一个Record实例,其状态就不能更改了。

与枚举一样,记录也是类的受限形式。它非常适合作为“数据载体”,即包含不想更改的数据的类,以及只包含最基本的方法(如构造函数和访问器)的类。

与前面介绍的其他预览特性一样,这个预览特性也顺应了减少Java冗余代码的趋势,能帮助开发者编写更精炼的代码。

一个示例类

定义一个长方形类

 final class Rectangle implements Shape {final double length;final double width;public Rectangle(double length, double width) {this.length = length;this.width = width;}double length() { return length; }double width() { return width; }}

它具有以下特点:

  • 所有字段都是final

  • 只包含构造器:Rectangle(double length, double width)和2个访问器方法:length()width()

您可以用record表示此类:

 record Rectangle(float length, float width) { }

一个record由一个类名称(在本例中为Rectangle)和一个record属性列表(在本示例中为float lengthfloat width)组成。

record会自动生成以下内容:

  • 为每个属性生成一个private final的字段

  • 为每个属性生成一个与组件名相同的访问方法;在本例中,这些方法是Rectangle::length()Rectangle::width()

  • 一个公开的构造函数,参数包括所有属性。构造函数的参数与字段对应。

  • equals()hashCode()方法的实现,如果两个record类型相同并且属性值相等,那么它们是相等的

  • toString()方法的实现,包括所有字段名和他们的值。

紧凑型构造函数

如果你想在record自定义一个构造函数。那么注意,它与普通的类构造函数不同,record的构造函数没有参数列表:这被称为紧凑型构造函数。

例如,下面的record``HelloWorld有一个字段message。它的自定义构造函数调用Objects.requireNonNull(message),如果message字段是用null值初始化的,则抛出NullPointerException。(自定义记录构造函数仍然会初始化所有字段)

 record HelloWorld(String message) {public HelloWorld {java.util.Objects.requireNonNull(message);}}

测试代码:

 @Testpublic void test() {HelloWorld h1 = new HelloWorld(null); // new HelloWorld("天地玄黄宇宙洪荒"); //用这个测试,可以发现字段还是会初始化的System.out.println(h1);}

这个测试代码执行报java.lang.NullPointerException异常。

使用限制

以下是record类使用的限制:

  • Record类不能继承任何类

  • Record类不能声明实例字段(与record组件相对应的 private final字段除外);任何其他声明的字段都必须是静态的

  • Record类不能是抽象的;它是final

  • Record类的成员变量是final

除了这些限制之外,record类的行为类似于常规类:

  • 可以在类中声明record;嵌套recordstatic

  • record可以实现接口

  • 使用new关键字实例化record

  • 您可以在record的主体中声明静态方法、静态字段、静态初始值设定项、构造函数、实例方法和嵌套类型

  • 可以对recordrecord的属性进行注释

record相关的API

java.lang.Class类有2个方法与record相关:

  • RecordComponent[] 返回类型getRecordComponents(): 返回record的所有字段列表。

  • boolean isRecord(): 与isEnum()类似,如果是record则返回true

2、JEP 394:模式匹配的 instanceof(正式特性)

JEP 394 (tools/javac

功能进化
Java版本特性类型JEP特性
Java 14预览特性JEP 305引入instanceof模式匹配为预览特性
Java 15预览特性JEP 375修正及优化,语法上同上一版没有区别
Java 16正式特性JEP 394成为正式特性

Java 14之前,instanceof主要用来检查对象的类型,检查匹配后,还需要对其进行类型强转才能使用该类型的变量,这显得很多余也很业余,而且存在手滑转错类型的可能。

Java SE 14instanceof操作符引入了模式匹配;如果instanceof运算符的结果为true,则判断对象将自动绑定到声明的变量上。

Java 14 之前的代码写法:

 if (obj instanceof String) {String s = (String) obj;// 业务逻辑}

在 Java 14 中,使用模式匹配的 instanceof,这可以被简化为:

 if (obj instanceof String s) {// 直接使用 s}

如果 objString 类型的实例,s 就会被自动声明并初始化为 obj 强制转换后的值。这样就避免了单独的类型转换步骤,并使得代码更加简洁易读。

 @Testpublic void test() {Object name = "初唐四杰";// 旧写法if (name instanceof String) {String s = (String) name;// 业务逻辑System.out.println(s);}​// 新写法if (name instanceof String s) {// 直接使用 sSystem.out.println(s);}    }
作用域

绑定变量的作用域一般是在instanceof内,但是在适当的条件下也可以扩展到外部

 @Testpublic void test() {Object name = "初唐四杰";    if (!(name instanceof Integer i)) {// 是为是!处理,不能直接使用 i,否则编译报错// System.out.println(i);return;}// 经过前面的return处理,i一定存在。这里可以使用i,你可以尝试将前面的return语句注释掉,看看,这里编译就报错了。因为情况变的不确定了。System.out.println(i);}
与运算符结合
 // 这个语句可以运行,因为&&是短路运算符,前面满足条件才会走到后面if (name instanceof Integer in && in > 10) {// 处理}

下面的语句编译不通过

 // 这个语句编译会报错,因为in不一定存在if (name instanceof Integer || in > 10) {// 处理}

3、JEP 397:密封的类和接口(第二次预览)

JEP 397

这仍是一个预览特性。

功能进化
Java版本特性类型JEP特性
Java 15预览特性JEP 360引入了密封类作为预览特性。
Java 16预览特性JEP 397第二次预览

密封的类和接口限制了哪些其他类或接口可以扩展或实现它们。

继承,作为面向对象语言的三大特性之一,我们工作过程中经常使用,可以重写父类的方法。

通常开发项目时,我们会先将接口提供出来,然后根据情况给出不同的基础实现类,子类再基础这些基础实现类进行扩展,我们可能并不希望子类直接继承接口,当然直接继承接口的写法从代码上看没有任何问题,但存在安全隐患。一般我们会通过开发约束对,这样的情况说一些要求,但是这样并不能杜绝这类问题。

密封类

为了进一步增强继承的限制能力,Java 15 引入密封类来精确控制类的继承问题 ,目前版本为预览特性。

什么是密封类

密封类的主要目的是提供一种更加精确地控制类继承的方法,通过这种方式,类的设计者可以指定一个类它能够被哪些类继承,它增强了类的封装性和安全性。由于密封类限制了类的继承,所以它使得代码更加可预测和易于维护。

  • 密封类(接口)用 sealed 修饰,则它的所有子类都必须在同一个模块或者包内,并且这些子类必须被显式地声明为该密封类的直接子类。

  • 密封类(接口)的子类可以被声明为non-sealed(非密封的)或final(最终的)。non-sealed的子类可以被进一步继承,而final的子类则不能。

  • 密封类(接口)使用 permits 来指定它的子类。

示例代码

这里我们以诗人为例,简化一下,我们这里只讨论汉朝诗人、唐朝诗人、宋朝诗人,代码如下:

 // 诗人基类public class Poet {}​// 汉朝诗人public class HanPoet extends Hero{}// 唐朝诗人public class TangPoet extends Poet{}​// 宋朝诗人public class SongPoet extends Hero{}​

接下来我们每个类别下面定义2个诗人:

  • 汉朝诗人(HanPoet):司马相如(SiMaXiangRu)、班固(BanGu)、

  • 唐朝诗人(TangPoet):李白(Libai)、杜甫(DuFu)

  • 宋朝诗人(SongPoet):苏轼(SuShi)、陆游(LuYou)

其中李白(Libai)继承自唐朝诗人(TangPoet),我们可以为唐朝诗人做一些公共处理,比如朝代是唐朝,但是有没有这种可能,有程序猿把李白的父类定义为诗人(Poet),那么我们为唐朝诗人定义的那些处理,李白就需要全部重新实现。这显然破坏了继承的实用性。

  • 使用 sealed 修饰Poetpermits 限定子类为: HanPoetTangPoetSongPoet ,只允许这3个类继承,如下:

 // 英雄基类,限制子类为:汉朝诗人(HanPoet)、唐朝诗人(TangPoet)、宋朝诗人(SongPoet)public sealed class Poet permits HanPoet,TangPoet,SongPoet {}
  • 第二层基类,继续使用 sealed 修饰

 // 汉朝诗人,限制子类为:司马相如(SiMaXiangRu)、班固(BanGu)public sealed class HanPoet extends Hero permits SiMaXiangRu,BanGu{}​// 唐朝诗人,限制子类为:李白(Libai)、杜甫(DuFu)public sealed class TangPoet extends Hero permits Libai,DuFu{}​// 宋朝诗人,限制子类为:苏轼(SuShi)、陆游(LuYou)public sealed class SongPoet extends Hero permits SuShi,LuYou{}
  • 第三层为具体诗人,他们继承第二层的诗人类型,使用extends继承即可,同时需要表示为non-sealedfinal,由于我们不希望类再往下了,所以定义为 final

 public final class SiMaXiangRu extends HanPoet{}​public final class Libai extends TangPoet{}​public final class SuShi extends SongPoet{}

这样,子类就不能随便继承父类了。

core-libs/java.util.stream

4、细微改动

(1)增加Stream.toList()方法(JDK-8180352 )

java.util.Stream中添加了一个新的方法toList。可以就可以不使用stream.collect(Collectors.toList())来转成List了。生成的是unmodifiableList,不可修改。

 @Testpublic void test() {// 出自《笠翁对韵》,与《声律启蒙》、和《训蒙骈句》合称吟诗作对三基。String str = "天对地,雨对风。大陆对长空。山花对海树,赤日对苍穹。雷隐隐,雾蒙蒙。日下对天中。风高秋月白,雨霁晚霞红。牛女二星河左右,参商两曜斗西东。十月塞边,飒飒寒霜惊戍旅;三冬江上,漫漫朔雪冷渔翁。"+ "河对汉,绿对红。雨伯对雷公。烟楼对雪洞,月殿对天宫。云叆叇,日曈朦。腊屐对渔蓬。过天星似箭,吐魄月如弓。驿旅客逢梅子雨,池亭人挹藕花风。茅店村前,皓月坠林鸡唱韵;板桥路上,青霜锁道马行踪。"+ "山对海,华对嵩。四岳对三公。宫花对禁柳,塞雁对江龙。清暑殿,广寒宫。拾翠对题红。庄周梦化蝶,吕望兆飞熊。北牖当风停夏扇,南檐曝日省冬烘。鹤舞楼头,玉笛弄残仙子月;凤翔台上,紫箫吹断美人风。";​List<String> list = Arrays.asList(str.split("。"));​List<String> result = list.stream().filter(s -> s.contains("对")).filter(e -> e.length() > 5).toList();​System.out.printf("list 长度:%s 数据:%s%n", result.size(), result);}

执行结果

 list 长度:6 数据:[天对地,雨对风, 山花对海树,赤日对苍穹, 河对汉,绿对红, 烟楼对雪洞,月殿对天宫, 山对海,华对嵩, 宫花对禁柳,塞雁对江龙]
Stream.toList()和stream.collect(Collectors.toList())的区别

Stream.toList()返回是一个unmodifiableList不可变的List,而使用Stream.collect(Collectors.toList())返回的是一个普通的List,是可以做增删改操作的。

(2)java.time包的格式化支持一天中的数据段(JDK-8180352 )

日期格式新增字母 B 表示一天中的时间段(day period)(转换规则按Unicode Locale Data Markup Language (LDML) Part 4: Dates中的规定),在类 java.time.format.DateTimeFormatter/DateTimeFormatterBuilder 中提供了支持,可以表示一天中的时间段,如"in the morning"(上午)或"at night"(晚上),而不仅仅是am/pm。

 // 时间是 13:45,输出:下午,其他还有上午、晚上等DateTimeFormatter.ofPattern("B").format(LocalTime.now())
(3)HttpClient的默认实现返回可取消的Future对象(JDK-8245462)

默认的HttpClient是通过调用HttpClient.newHttpClient()或调用HttpClient.newBuilder()返回的构建器再调用build方法创建的。默认HttpClientsendAsync方法的实现现在返回可取消的CompletableFuture对象。对未完成的可取消未来调用cancel(true),会尝试取消HTTP请求,以尽快释放底层资源。可以参考HttpClient::sendAsync方法的API文档。

上面创建HttpClient的方法可能抛出UncheckedIOException异常(JDK-8248006)。

(4)修正Path.ofPaths.get的第一个参数为null时不会抛出空指针异常的问题(JDK-8254876)

之前的版本中,Path.of()Paths.get()方法的参数有多个时,第一个参数并没有进行不能为null的检查。在这个版本中,如果第一个参数为null则会跟其他参数为null一样抛出NullPointerException

5、JEP 338:向量 API(孵化器特性)

JEP 338 (hotspot/compiler

提供孵化模块jdk.incultor.vector的初始迭代,以表示在运行时可靠地编译为支持的CPU架构上的最佳向量硬件指令的向量计算,从而实现优于等效标量计算的性能。

6、JEP 347:启用 C++14 语言特性

JEP 347

JDK 的某些组件,特别是 Java 虚拟机(JVM),是采用 C++ 语言开发的。随着 C++ 的不断演进,新标准的推出带来了诸多有益的特性,比如改进的类型推断、智能指针和 lambda 表达式等,这些特性对于提升代码品质和开发效率都有显著作用。然而,JDK 的开发过程中主要还停留在使用较为旧版 C++ 标准(例如 C++98),这限制了可利用的语言功能的广度。

随着 Java 16C++14 的支持,这象征着 JDK 开发者在编写 JDK 源码时可以借助 C++14 的标准特性,从而有望提高 JDK 的开发效率和代码质量。

7、JEP 357:将JDK的源代码库从Mercurial迁移到Git

JEP 357

8、JEP 369:将JDK的源代码库托管到GitHub

JEP 369

9、JEP 376:ZGC 并发线程处理

JEP 376 (hotspot/gc)

ZGC 是 Java 11 中引入的一个实验性垃圾收集器,设计目标是实现低延迟一个可伸缩的、低延迟的垃圾收集器。在 Java 11 到 Java 15 期间,ZGC 已经表现出了卓越的低延迟特性,但在某些情况下,它需要暂停应用线程来处理堆中的引用。

Java 16 引入并发线程处理,旨在将这些暂停转变为并发处理,以进一步降低延迟。该特性的核心是将 ZGC 中的最后一块堆管理工作 — 引用处理(Reference Processing) — 转变为并发执行。

功能进化
java版本特性类型JEP特性
Java 11预览特性JEP 333引入 ZGC 作为实验特性
Java 15正式特性JEP 377成为正式特性
Java 16正式特性JEP 376并发线程处理

10、JEP 380:Unix-Domain 套接字通道

JEP 380 (core-libs/java.nio)

java.nio.channelsSocketChannelServerSocketChannel类中提供对Unix域套接字(AF_Unix)的支持。

11、JEP 386:AlpineLinux 移植

JEP 386

12、JEP 387:弹性元空间

JEP 387 (hotspot/runtime)

在 Java 8 中,元空间替代了原有的永久代(PermGen),成为存储类元数据的区域。虽然这一改变解决了永久代大小限制的问题,但元空间的内存管理依然不够高效,特别是在类卸载后释放内存方面。Java 16 引入弹性元空间,目的是进一步提高元空间的内存使用效率,特别是在动态加载和卸载类的应用场景中。

弹性元空间彻底检修了VM内部元空间和类空间的实现。用于类元数据的内存较少。节省的效果在涉及大量小粒度类加载器的场景中最为明显。类卸载后,内存会及时返回到操作系统。

添加了一个开关来微调元空间回收:-XX:MetaspaceReclaimPolicy=(balanced|aggressive|none),默认是balanced,使虚拟机回收内存,同时将计算开销保持在最低限度;激进地适度提高回收率,代价是记账成本略高;没有一个完全关闭回收。

开关InitialBootClassLoaderMetaspaceSizeUseLargePagesInMetaspace已被弃用。

13、JEP 388:Windows/AArch64 移植

JEP 388

将JDK移植到Windows/AArch64。

14、JEP 389:外部函数与内存 API(孵化特性)

JEP 389 (core-libs

孵化阶段。

功能进化
java版本特性类型JEP特性
Java 14孵化特性JEP 370引入了外部内存访问 API作为孵化特性
Java 15第二次孵化JEP 383优化外部内存访问 API
Java 16孵化特性JEP 389引入了外部链接器 API
Java 16第三次孵化JEP 393功能优化

引入一个API,它提供对本机代码的静态类型的纯Java访问。此API与Foreign-Memory API(JEP 393)一起,将大大简化绑定到本机库的错误处理过程。

15、JEP 390:对基于值的类发出警告

JEP 390 (core-libs

Java 16@jdk.internal.ValueBased注解加入了基于值的类的告警。

将基础类的包装类指定为基于值的,弃用其构造函数以表示降落会删除(Java 9注解@Deprecated得到了增强,增加了 since 和 forRemoval 两个属性,可以分别指定一个程序元素被废弃的版本,以及是否会在今后的版本中被删除。),从而提示新的弃用警告。Java平台中任何基于值的类的实例上进行Synchronized操作,编译时将产生警告。

Java 16引入该特性的主要目的是警告开发者关于基于值的类的使用。基于值的类是一种特殊类型的类,它们的实例是不可变的。应该当成,单纯的数据载体,不应该被视为类的实例。

当我们尝试进行同步(使用synchronized关键字)时,编译器会发出警告,比如:

 public void test1(Integer count) {for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (count) { // 这里会产生编译告警}}).start();}}

该特性通过告警的方式,引导开发者更好地理解和利用基于值的类,为未来 Java 版本中可能的优化和特性变化做好准备。

警告信息:

 Integer is a value-based type which is a discouraged argument for the synchronized statement

16、JEP 392:打包工具(正式特性)

JEP 392 (tools/jpackage

功能进化
java版本特性类型JEP特性
Java 14孵化特性JEP 343引入了打包工具孵化特性
Java 16正式特性JEP 392成为正式特性

Java 14之前,Java 应用一般使用JAR包的形式进行分发和运行,或者需要第三方工具来创建本地应用程序包,Java 14引入一个新的打包工具:基于 javapackagerjpackage,用于打包Java应用程序为特定平台的本地安装包。但是在Java 14中它是作为一个孵化特性引入的,在Java 16中作为正式特性发布。

前置条件

事先准备

  • JAVA 16版本以上

  • Windows系统下使用jpackage指令需要用到WiX,版本3.0及以上,并配置好PATH变量;

  • java程序提前打包成jar文件

如果没有安装WiX,使用jpackage打包时会提示:

imageb77eacc728e3faf9.png

安装.Net Framework 3

WiX依赖于.Net Framework 3,所以如果之前没有安装,那么在装Wix之前需要先安装.Net Framework 3

安装步骤: 1、控制面板的“程序和功能”中点击“启用和关闭Windows功能” 2、勾选.NET Framework 3.5(包括.NET 2.0 和 3.0),点击确定,再点击同意下载 3、等待自动下载并安装完成 4、最后重新启动计算机

image1dfb23dd97e5dada.png

安装WiX

下载地址:WiX v3 | WiX Toolset

下载完成后,点击exe文件,选择Install。等待安装完成。

imaged254ecbb6e551f2e.png

出现Complete即完成。

imageaff2f65e29721524.png

默认安装位置:C:\Program Files (x86)\WiX Toolset v3.14 配置环境变量:在Path中增加C:\Program Files (x86)\WiX Toolset v3.14\bin

image1cf962ae4a53251e.png

 1、生成运行程序:jpackage --type app-image --input [Jar包所在文件夹] --runtime-image [Jre文件夹] --name [应用名称] --main-jar [可执行Jar包] --icon [程序图标的路径] --app-version [版本号] --vendor [程序供应商的名称] --copyright [版权信息] --description [应用描述] --dest [输出目录]2、生成安装程序:jpackage --type msi --win-dir-chooser --name [安装程序的名称] --app-image [运行程序的文件夹] --dest [输出目录]

 "F:\Program Files\Java\jdk-21.0.2\bin\jlink" --add-modules java.base,java.desktop --output myjre"F:\Program Files\Java\jdk-21.0.2\bin\jpackage" --name myapp --runtime-image myjre --input . --main-jar mytest-pkg-1.0.0-SNAPSHOT.jar​"F:\Program Files\Java\jdk-21.0.2\bin\jpackage" --name myapp --runtime-image myjre --input . --main-jar mytest-pkg-1.0.0-SNAPSHOT.jar \--win-dir-chooser --win-menu --win-per-user-install --win-shortcut --win-shortcut-prompt

image6b4781e92b08a929.png

jpackage -h 输出帮助信息

 用法:jpackage <options>​示例用法:--------------生成适合主机系统的应用程序包:对于模块化应用程序:jpackage -n name -p modulePath -m moduleName/className对于非模块化应用程序:jpackage -i inputDir -n name \--main-class className --main-jar myJar.jar从预构建的应用程序映像:jpackage -n name --app-image appImageDir生成应用程序映像:对于模块化应用程序:jpackage --type app-image -n name -p modulePath \-m moduleName/className对于非模块化应用程序:jpackage --type app-image -i inputDir -n name \--main-class className --main-jar myJar.jar要为 jlink 提供您自己的选项,请单独运行 jlink:jlink --output appRuntimeImage -p modulePath \--add-modules moduleName \--no-header-files [<additional jlink options>...]jpackage --type app-image -n name \-m moduleName/className --runtime-image appRuntimeImage生成 Java 运行时程序包:jpackage -n name --runtime-image <runtime-image>​一般选项:@<filename>从文件读取选项和/或模式可以多次使用此选项。--type -t <type>要创建的程序包的类型有效值为:{"app-image", "exe", "msi"}如果未指定此选项,则将创建与平台相关的默认类型。--app-version <version>应用程序和/或程序包的版本--copyright <copyright string>应用程序的版权--description <description string>应用程序的说明--help -h将用法文本输出到输出流并退出,用法文本中包含适用于当前平台的每个有效选项的列表和说明--icon <file path>应用程序包图标的路径(绝对路径或相对于当前目录的路径)--name -n <name>应用程序和/或程序包的名称--dest -d <destination path>用来放置所生成的输出文件的路径(绝对路径或相对于当前目录的路径)默认为当前的工作目录。--temp <directory path>用来创建临时文件的新目录或空白目录的路径(绝对路径或相对于当前目录的路径)如果指定,则在任务完成时将不删除临时目录,必须手动删除临时目录。如果未指定,则将创建一个临时目录,并在任务完成时删除该临时目录。--vendor <vendor string>应用程序的供应商--verbose启用详细的输出--version将产品版本输出到输出流并退出。​用来创建运行时映像的选项:--add-modules <模块名称>[,<模块名称>...]要添加的模块的逗号 (",") 分隔列表此模块列表连同主模块(如果指定)将作为 --add-module 参数传递到 jlink。如果未指定,则仅使用主模块(如果指定了 --module),或者使用默认的模块集(如果指定了--main-jar)。可以多次使用此选项。--module-path -p <module path>...路径的 ; 分隔列表每个路径要么是模块的目录,要么是模块化 jar 的路径。(每个路径可以是绝对路径,也可以是相对于当前目录的路径。)可以多次使用此选项。--jlink-options <jlink 选项>要传递给 jlink 的选项列表(用空格分隔)如果未指定,则默认为 "--strip-native-commands--strip-debug --no-man-pages --no-header-files"。可以多次使用此选项。--runtime-image <directory path>将复制到应用程序映像的预定义运行时映像的路径(绝对路径或相对于当前目录的路径)如果未指定 --runtime-image,jpackage 将运行 jlink 以使用如下选项创建运行时映像:--strip-debug、--no-header-files、--no-man-pages 和--strip-native-commands。​用来创建应用程序映像的选项:--input -i <directory path>包含要打包的文件的输入目录的路径(绝对路径或相对于当前目录的路径)输入目录中的所有文件将打包到应用程序映像中。--app-content <additional content>[,<additional content>...]要添加到应用程序有效负载中的文件和/或目录的逗号分隔路径列表。此选项可以多次使用。​用来创建应用程序启动程序的选项:--add-launcher <launcher name>=<file path>启动程序的名称和包含关键字-值对列表的属性文件的路径(绝对路径或相对于当前目录的路径)可以使用关键字 "module"、"main-jar"、"main-class"、"description"、"arguments"、"java-options"、"app-version"、"icon"、"launcher-as-service"、"win-console"、"win-shortcut"、"win-menu"、"linux-app-category" 和 "linux-shortcut"。这些选项将添加到原始命令行选项中或者用来覆盖原始命令行选项,以构建额外的替代启动程序。将从命令行选项构建主应用程序启动程序。可以使用此选项构建额外的替代启动程序,可以多次使用此选项来构建多个额外的启动程序。--arguments <main class arguments>在没有为启动程序提供命令行参数时,要传递到主类的命令行参数可以多次使用此选项。--java-options <java options>要传递到 Java 运行时的选项可以多次使用此选项。--main-class <class name>要执行的应用程序主类的限定名称只有在指定了 --main-jar 时才能使用此选项。--main-jar <main jar file>应用程序的主 JAR;包含主类(指定为相对于输入路径的路径)可以指定 --module 或 --main-jar 选项,但是不能同时指定两者。--module -m <module name>[/<main class>]应用程序的主模块(以及可选的主类)此模块必须位于模块路径中。如果指定了此选项,则将在 Java 运行时映像中链接主模块。可以指定 --module 或 --main-jar 选项,但是不能同时指定这两个选项。​用来创建应用程序启动程序的与平台相关的选项:--win-console为应用程序创建控制台启动程序,应当为需要控制台交互的应用程序指定​用来创建应用程序包的选项:--about-url <url>应用程序主页的 URL--app-image <directory path>用来构建可安装程序包的预定义应用程序映像的位置(绝对路径或相对于当前目录的路径)--file-associations <file path>包含关键字-值对列表的属性文件的路径(绝对路径或相对于当前目录的路径)可以使用关键字 "extension"、"mime-type"、"icon" 和 "description"来描述此关联。可以多次使用此选项。--install-dir <directory path>默认安装位置下面的相对子路径--license-file <file path>许可证文件的路径(绝对路径或相对于当前目录的路径)--resource-dir <directory path>覆盖 jpackage 资源的路径可以通过向该目录中添加替代资源来覆盖 jpackage 的图标、模板文件和其他资源。(绝对路径或相对于当前目录的路径)--runtime-image <directory path>要安装的预定义运行时映像的路径(绝对路径或相对于当前目录的路径)在创建运行时程序包时需要使用选项。--launcher-as-service请求创建安装程序,以将主应用程序启动程序注册为后台服务类型应用程序。​用来创建应用程序包的与平台相关的选项:--win-dir-chooser添加一个对话框以允许用户选择产品的安装目录。--win-help-url <url>用户可以从中获取更多信息或技术支持的 URL--win-menu请求为此应用程序添加开始菜单快捷方式--win-menu-group <menu group name>此应用程序所在的开始菜单组--win-per-user-install请求基于每个用户执行安装--win-shortcut请求为此应用程序添加桌面快捷方式--win-shortcut-prompt添加一个对话框以允许用户选择是否将由安装程序创建快捷方式。--win-update-url <url>可用应用程序更新信息的 URL--win-upgrade-uuid <id string>与此程序包的升级相关联的 UUID

17、JEP 393:外部存储器访问 API(第三次孵化)

JEP 393 (core-libs

孵化阶段。

功能进化
java版本特性类型JEP特性
Java 14孵化特性JEP 370引入了外部内存访问 API作为孵化特性
Java 15第二次孵化JEP 383优化外部内存访问 API
Java 16孵化特性JEP 389引入了外部链接器 API
Java 16第三次孵化JEP 393功能优化

18、JEP 396:默认强封装 JDK 内部元素

JEP 396 (core-libs

在 Java 16 之前,许多 JDK 内部的类和成员尽管没有正式成为公共 API,但仍然可以被外部代码所访问。从 Java 16 开始,默认情况下,这些内部 API 被强制封装,阻止了对它们的非法访问,但关键的内部API(如sun.misc.Unsafe)除外。防止开发者依赖于非稳定的、未经官方支持的内部实现,提高了代码的长期稳定性。

启动器选项的默认值--illegal-access 现在是deny而不是permit。这可能造成,那些使用了JDK内部的类、方法或字段的大多数代码将无法运行。临时可以通过指定--illegal-access=permit在JDK16上运行。但是,该选项将在将来的版本中删除 。

Java 16 明确了哪些是公共 API,哪些是 JDK 内部使用的 API,帮助开发者避免依赖于可能在未来版本中改变的内部实现。鼓励开发者使用稳定且官方支持的公共 API,而不是依赖于内部的、可能随时变更的实现。

19、移除的APIs、工具、容器

参考:

  • Java SE 16中移除的API

  • JDK 16中移除的特性和容器

Oracle JDK和OpenJDK之间的差异

尽管官方已经声明了让OpenJDKOracle JDK二进制文件尽可能接近的目标,但至少对于JDK 16来说,这两者之间仍然存在一些差异。

目前的差异是:

  • Oracle JDK提供了安装程序(msirpmdeb等),它们不仅将JDK二进制文件放置在系统中,还包含更新规则,在某些情况下还可以处理一些常见的配置,如设置常见的环境变量(如Windows中的JAVA_HOME)和建立文件关联(如使用JAVA启动.jar文件)。OpenJDK仅作为压缩档案(tar.gz.zip)提供。

  • Usage Logging仅在Oracle JDK中可用。

  • Oracle JDK要求使用Java加密扩展(JCE(Java Cryptography Extension ))代码签名证书对第三方加密提供程序进行签名。OpenJDK继续允许使用未签名的第三方加密提供程序。

  • java -version命令输出结果不同。Oracle JDK将输出java并包含LTS。Oracle生成的OpenJDK将显示OpenJDK,不包括Oracle特定的LTS标识符。

  • Oracle JDK将在OTN许可证下发布。任何许可证文件都需要指向OTNOpenJDK将在GPLv2wCP下发布,并将包括GPL许可证。

  • Oracle JDK将在FreeType许可证下分发FreeType,而OpenJDK则将在GPLv2下分发。因此,\legal\java.desktop\freetype.md的内容将有所不同。

  • Oracle JDKJava cupsteam图标,而OpenJDK有Duke图标。

  • Oracle JDK源代码包括ORACLE PROPRIETARY/CONFIDENTIAL. 使用受许可条款约束的说明(OTN(Oracle Technology Network License Agreement for Oracle Java SE )协议),OpenJDK源代码包含GPL协议。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com