来了来了,Java14它真的来了

简介: 语言必须发展,否则它们就有变得无关紧要的风险,” Brian Goetz (甲骨文公司)在2019年11月在 Devoxx 举行的“ Java 语言期货”演讲中说。 作为 Java 语言架构师,他扮演了一个重要的角色,尽管 Java 已经发展了25年,但仍然远远没有过时。

在这里插入图片描述

语言必须发展,否则它们就有变得无关紧要的风险,” Brian Goetz (甲骨文公司)在2019年11月在 Devoxx 举行的“ Java 语言期货”演讲中说。 作为 Java 语言架构师,他扮演了一个重要的角色,尽管 Java 已经发展了25年,但仍然远远没有过时。 在本文中,我们将研究 JDK 14的创新

作者: Falk Sippach

文章出处:Java – the fourteenth

近年来,甲骨文做出了一些突破性的决定。 他们包括新的半年发布模式与预览功能和更短的发布和反馈周期的新功能。 许可模式也发生了变化,Oracle JDK 不再免费提供。 这加剧了竞争,因此您现在可以从包括 Oracle 在内的各种供应商获得免费的 OpenJDK 发行版。 自从 java11以来,它已经与 oraclejdk 实现了二进制兼容,并且采用开源许可证。

一年半以前,最后一个 LTS 版本 Java 11于2019年秋季发布。 从那时起,随后的两个主要版本只有有限数量的新特性。 JDK 孵化器项目(Amber, Valhalla, Loom …) ,然而,正在致力于许多新想法,所以不足为奇的是,刚刚发布的 JDK 14的功能范围再次显著扩大。 即使只有少数人会在生产环境中使用新版本,您仍然应该关注新特性,并尽早就预览功能提供反馈。 这是确保新特性投入生产直到下一个 LTS 版本最终完成的唯一方法,该版本将在2021年秋季以 Java 17的形式发布。

下列Java增强建议(JEP)已经实现。在本文中,我们将从开发人员的角度来仔细研究感兴趣的主题。

  • JEP 305: Pattern Matching for instanceof (Preview)
  • JEP 343: Packaging Tool (Incubator)
  • JEP 345: NUMA-Aware Memory Allocation for G1
  • JEP 349: JFR Event Streaming
  • JEP 352: Non-Volatile Mapped Byte Buffers
  • JEP 358: Helpful NullPointerExceptions
  • JEP 359: Records (Preview)
  • JEP 361: Switch Expressions (Standard)
  • JEP 362: Deprecate the Solaris and SPARC Ports
  • JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
  • JEP 364: ZGC on macOS
  • JEP 365: ZGC on Windows
  • JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination
  • JEP 367: Remove the Pack200 Tools and API
  • JEP 368: Text Blocks (Second Preview)
  • JEP 370: Foreign-Memory Access API (Incubator)

JEP 305: Pattern matching for instanceof

自20世纪60年代以来,模式匹配语言的概念已经在各种编程语言中得到了应用。 其中最现代的例子是 Haskell 和 Scala。 模式是一个谓词的组合,该谓词匹配目标结构和该模式中的一组变量。 如果这些变量匹配,则为它们分配相应的内容。 其目的是破坏对象,也就是将它们分解为它们的组件。

到目前为止,Java 只能区分 switch 语句中的数据类型 integer、 string 和 enum。 然而,随着 Java 12中开关表达式的引入,迈向模式匹配的第一步已经迈出。 使用 Java 14,我们现在可以额外地使用模式匹配操作符 instanceof。 避免了不必要的强制转换,减少的冗余提高了可读性。

例如,在此之前,必须按照以下步骤检查空字符串或空集合:

boolean isNullOrEmpty( Object o ) {
  return == null ||
    instanceof String && ((String) o).isBlank() ||
    instanceof Collection && ((Collection) o).isEmpty();
}

现在您可以在使用 instanceof 检查时直接将值赋给变量,并对其执行进一步调用:

boolean isNullOrEmpty( Object o ) {
  return o == null ||
    o instanceof String s && s.isBlank() ||
    o instanceof Collection c && c.isEmpty();
}

这种区别似乎微不足道,然而,Java 开发人员中的纯粹主义者节省了一个小而烦人的冗余。

开关表达式最早是在 Java 12和13中引入的,在这两种情况下都是作为一个预览特性。 它们现已在 jep361中最后确定。 这为开发人员提供了两种新的语法变体,它们具有更短、更清晰和更不容易出错的语义。 表达式的结果可以分配给变量,或者作为方法的值返回(清单1)。

JEP 358: Helpful NullPointerExceptions

对空引用的无意访问也是 Java 开发人员所担心的。 根据托尼•霍尔爵士(Sir Tony Hoare)自己的说法,他发明的零Y引用是一个错误,其后果高达数十亿美元。 这仅仅是因为在20世纪60年代阿尔戈语的发展过程中,它是如此容易实现。

在 Java 中,编译器和运行时环境都不支持处理零引用。 这些恼人的异常可以通过各种变通方法来避免。 最简单的方法是将检查设置为零。 不幸的是,这个过程非常繁琐,当我们需要它的时候我们往往会忘记它。 使用自 JDK 8以来包含的包装器类 Optional,您可以通过 API 显式地告诉调用者,一个值可以为零,并且它必须对此进行响应。 因此,您不能再意外地遇到空引用,而必须显式地处理可能为空的值。 这个过程对于公共接口的返回值非常有用,但是也会消耗额外的间接层,因为您总是需要解压实际值。

在其他语言中,辅助工具早已构建到语法和编译器中,比如Groovy中 NullObjectPattern 和 Safe Navigation 操作符(some?.method())。 在 Kotlin,可以明确区分可能不为空的类型和可能作为引用为 null 的类型。 我们将来也必须使用 Java 中的 nullpointerexception。 但是,作为预览特性引入的有用的NullPointerExceptions可以简化异常的故障排除。 为了在抛出 NullPointerException 时插入必要的信息,必须在启动时激活选项 -XX: + ShowCodeDetailsInExceptionMessages。 如果调用链中的一个值为零,那么您将收到一条有用的消息:

man.partner().name()
 
Result: java.lang.NullPointerException: Cannot invoke "Person.name()" because the return value of "Person.partner()" is null

Lambda表达式需要特殊处理。 例如,如果lambda函数的参数为零,则默认情况下将收到清单2所示的错误消息。要显示正确的参数名称,必须使用-g:vars选项编译源代码。 结果如下:

java.lang.NullPointerException: Cannot invoke "Person.name()" because "p" is null
Listing 2 清单2
Stream.of( man, woman )
  .map( p -> p.partner() )
.map( p -> p.name() )
.collect( Collectors.toUnmodifiableList() );
 
Result: java.lang.NullPointerException: Cannot invoke "Person.name()" because "<parameter1>" is null

不幸的是,当一个空参数时,目前没有方法引用的指示:

Stream.of( man, woman )
  .map( Person::partner )
  .map( Person::name )
  .collect( Collectors.toUnmodifiableList() )
Result: java.lang.NullPointerException

但是,如本例所示,如果将每个流方法调用放在新行中,那么麻烦的代码行可以很快地缩小范围。 NullPointerExceptions在自动装箱/拆箱中也具有挑战性。 如果在这里也激活了编译器参数-g:vars,您还将收到新的有用的错误消息(清单3)。

Listing 3 清单3
int calculate() {
  Integer a = 2, b = 4, x = null;
  return a + b * x;
}
calculate();
Result: java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "x" is null

JEP 359: Records

也许最令人兴奋的同时也是最令人惊讶的创新是记录类型的引入 。 它们是在Java 14发行中相对较晚实现的,是一种类声明的限制形式,类似于枚举。 记录是在Valhalla项目中开发的。 与Kotlin中的Data Classes和Scala中的Case Classes有某些相似之处。 紧凑的语法可能会使Lombok之类的库在将来过时。 Kevlin Henney还看到了以下优点:“我认为Java记录功能的有趣的副作用之一是,实际上,它将帮助揭示多少Java代码实际上是面向 getter / setter而非面向对象的。” 一个人有两个字段的简单定义可以在这里看到 :

public record Person( String name, Person partner ) {}

一个带有附加构造函数的扩展变量,因此只有字段*name* 是强制的,也可以实现:

public record Person( String name, Person partner ) {
  public Person( String name ) { this( name, null ); }
  public String getNameInUppercase() { return name.toUpperCase(); }
}

编译器生成一个不可变类,除了这两个属性和它自己的方法之外,它还包含访问器的实现(没有 getter!) 、构造函数 equals / hashcode 和 toString (清单4)。

Listing 4 清单4
public final class Person extends Record {
  private final String name;
  private final Person partner;
   
  public Person(String name) { this(name, null); }
  public Person(String name, Person partner) { this.name = name; this.partner = partner; }
 
  public String getNameInUppercase() { return name.toUpperCase(); }
  public String toString() { /* ... */ }
  public final int hashCode() { /* ... */ }
  public final boolean equals(Object o) { /* ... */ }
  public String name() { return name; }
  public Person partner() { return partner; }
}

使用的行为符合预期,您无法从调用方判断记录类型是实例化的(清单5)。

Listing 5 清单5
var man = new Person("Adam");
var woman = new Person("Eve", man);
woman.toString(); // ==> "Person[name=Eve, partner=Person[name=Adam, partner=null]]"
 
woman.partner().name(); // ==> "Adam"
woman.getNameInUppercase(); // ==> "EVE"
 
// Deep equals
new Person("Eve", new Person("Adam")).equals( woman ); // ==> true

顺便说一下,records 不是经典的 javabean,因为它们不包含真正的 getter。 但是,您可以使用相同名称的方法访问成员变量。 记录也可以包含注释或 Javadocs。 此外,还可以在主体中声明静态字段、方法、构造函数或实例方法。 不允许在记录头之外定义其他实例字段。

JEP 368: Text Blocks

最初计划作为 java12的原始字符串,java13引入了一个更轻量级的版本,称为文本块的多行字符串的形式。 特别是对于 HTML 模板和 SQL 脚本,它们极大地提高了可读性(清单6)。

Listing 6 清单6

// 未使用 Text Blocks
String html = "<html>\n" +
              "    <body>\n" +
              "        
 
Hello, Escapes
 
\n" +
              "    </body>\n" +
              "</html>\n";
 
// With Text Blocks
String html = """
              <html>
                  <body>
                       
 
Hello, Text Blocks
 
                  </body>
              </html>""";Listing 6 清单6

// Without Text Blocks
String html = "<html>\n" +
              "    <body>\n" +
              "        
 
Hello, Escapes
 
\n" +
              "    </body>\n" +
              "</html>\n";
 
// 使用 Text Blocks
String html = """
              <html>
                  <body>
                       
 
Hello, Text Blocks
 
                  </body>
              </html>""";

还添加了两个新的转义序列,您可以使用它们调整文本块的格式。 例如,如果要使用不应在输出中显式出现的换行符,则只需在行尾插入(反斜杠)即可。 这为您提供了一个带有长行的字符串,但是为了清楚起见,您可以在源代码中使用换行符(清单7)。

Listing 7 清单7

String text = """
                Lorem ipsum dolor sit amet, consectetur adipiscing \
                elit, sed do eiusmod tempor incididunt ut labore \
                et dolore magna aliqua.\
                """;
// 代替+
String literal = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
                 "elit, sed do eiusmod tempor incididunt ut labore " +
                 "et dolore magna aliqua.";

新的转义序列\ s被转换为空格。 例如,这可以用于确保行尾的空白不会被自动截断(修剪),并获得每行固定的字符宽度:

String colors = """
    red  \s
    green\s
    blue \s
    """;

还有什么新鲜事吗?

除了所描述的功能(对于开发人员来说主要是有趣的)之外,还有其他一些更改。 在JEP 352中,对FileChannel API进行了扩展,以允许创建MappedByteBuffer实例。 与易失性存储器(RAM)不同,它们在非易失性数据存储(NVM,非易失性存储器)上工作。 但是,目标平台是Linux x64。 关于垃圾收集也发生了很多事情。 并发标记扫描(CMS)垃圾收集器已被删除。 因此,ZGC现在也可用于macOS和Windows。

对于关键的Java应用程序,建议在生产中激活飞行记录功能。 以下命令使用Flight Recording启动Java应用程序,并将信息写入record.jfr,并始终保留一天的数据:

java \
-XX:+FlightRecorder \
-XX:StartFlightRecording=disk=true, \
filename=recording.jfr,dumponexit=true,maxage=1d \
-jar application.jar

通常,您随后可以使用工具JDK Mission Control(JMC)读取和分析数据。 JDK 14的另一个新功能是,您还可以从应用程序异步查询事件(清单8)。

Listing 8 清单8
import jdk.jfr.consumer.RecordingStream;
import java.time.Duration;
 
try ( var rs = new RecordingStream() ) {
  rs.enable( "jdk.CPULoad" ).withPeriod( Duration.ofSeconds( 1 ) );
  rs.onEvent( "jdk.CPULoad", event -> {
    System.out.printf( "%.1f %% %n", event.getFloat( "machineTotal" ) * 100 );
  });
  rs.start();
}

在JDK 8中,我们拥有工具javapackager,但是不幸的是,它在版本11中与JavaFX一起从Java中删除。 现在,在Java 14中引入了后继jpackage(JEP 343:打包工具),利用它我们可以再次创建独立的Java安装文件。 它们的基础是包括运行时环境的Java应用程序。 该工具使用此输入来构建包含所有依赖项的可执行二进制工件(格式:dmg中的msi,exe,pkg,dmg中的app,deb和rpm)。

总结

Java没有死,Java万岁! 半年两次的OpenJDK版本使语言和平台都受益。 这次,新功能比Java 12和13还要多。而且,仍有许多功能需要在将来的版本中实现。 因此,我们的Java开发人员不会感到无聊,并且未来的前景仍然一片光明。 到2020年9月,我们可以预见Java 15的到来。

目录
相关文章
|
机器学习/深度学习 存储 PyTorch
【AMP实操】解放你的GPU运行内存!在pytorch中使用自动混合精度训练
【AMP实操】解放你的GPU运行内存!在pytorch中使用自动混合精度训练
2018 0
|
Java Spring
IDEA中使用org.springframework.boot.autoconfigure.AutoConfiguration.imports没有被识别
IDEA中使用org.springframework.boot.autoconfigure.AutoConfiguration.imports没有被识别
1535 0
|
2月前
|
数据采集 人工智能 算法
咖啡馆对谈:AI算法狂飙时代,医疗器械(如呼吸机)GEO优化的破局之路
本文以咖啡馆对谈形式,生动呈现AI搜索时代医疗器械GEO优化的破局之道。聚焦呼吸机行业,提出“GEO高维场景理论”:通过叠加人群、用途、属性等多维度,精准匹配用户真实需求,避开泛词红海,提升AI推荐率与转化效率。同时厘清媒体可信度分级,给出可落地的四步执行方案。
201 0
|
11月前
|
人工智能 自然语言处理 数据可视化
大型企业如何建好用好 BI 系统?方案与价值双解析
在数据驱动时代,BI系统已成为企业决策的核心。本文综述主流BI工具,重点解析瓴羊Quick BI的智能分析、多端协同与AI Agent能力,助力企业高效构建现代化BI体系。
|
9月前
|
人工智能 监控 安全
大模型备案安全合规实践指南:从模型训练到部署的全链路解析
大模型的安全与合规并非一蹴而就的静态认证,而是一个需要持续投入、动态优化的核心能力建设过程,它贯穿于数据准备、模型训练、部署推理到应用监控的全生命周期。
584 4
|
10月前
|
数据采集 机器学习/深度学习 人工智能
未来趋势:AI 时代下 python 爬虫技术的发展方向
未来趋势:AI 时代下 python 爬虫技术的发展方向
|
人工智能 运维 安全
从被动防御到主动免疫进化!迈格网络 “天机” AI 安全防护平台,助推全端防护性能提升
迈格网络推出“天机”新版本,以AI自学习、全端防护、主动安全三大核心能力,重构网络安全防线。融合AI引擎与DeepSeek-R1模型,实现威胁预测、零日防御、自动化响应,覆盖Web、APP、小程序全场景,助力企业从被动防御迈向主动免疫,护航数字化转型。
从被动防御到主动免疫进化!迈格网络 “天机” AI 安全防护平台,助推全端防护性能提升
|
存储 编译器 程序员
【C语言】auto 关键字详解
`auto` 关键字用于声明局部变量的自动存储类,其作用主要体现在变量的生命周期上。尽管现代C语言中 `auto` 的使用较少,理解其历史背景和作用对于掌握C语言的存储类及变量管理仍然很重要。局部变量默认即为 `auto` 类型,因此在实际编程中,通常不需要显式声明 `auto`。了解 `auto` 关键字有助于更好地理解C语言的存储类及其在不同场景中的应用。
1087 1
|
数据采集 自动驾驶 机器人
数据喂得好,机器人才能学得快:大数据对智能机器人训练的真正影响
数据喂得好,机器人才能学得快:大数据对智能机器人训练的真正影响
1235 1
|
人工智能 Kubernetes Devops
VMware vSphere 8.0 Update 3g 下载 - 企业级工作负载平台
VMware vSphere 8.0 Update 3g 下载 - 企业级工作负载平台
1002 0
VMware vSphere 8.0 Update 3g 下载 - 企业级工作负载平台