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 394(instanceof的模式匹配 (正式特性))、JEP 395(Record类)、JEP 397(密封类(第二次预览))等。

下载地址

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

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

Java16新特性总结

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

JEP 395tools/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);
     }
 }

测试代码:

 @Test
 public 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 394tools/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 强制转换后的值。这样就避免了单独的类型转换步骤,并使得代码更加简洁易读。

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

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

 @Test
 public 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,不可修改。

 @Test
 public 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 338hotspot/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 389core-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 390core-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 392tools/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 393core-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 396core-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、工具、容器

参考:

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协议。

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值