来了来了,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 语句中的数据类型 integerstringenum。 然而,随着 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中 NullObjectPatternSafe 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 ClassesScala中的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现在也可用于macOSWindows

对于关键的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中引入了后继jpackageJEP 343:打包工具),利用它我们可以再次创建独立的Java安装文件。 它们的基础是包括运行时环境的Java应用程序。 该工具使用此输入来构建包含所有依赖项的可执行二进制工件(格式:dmg中的msiexepkgdmg中的appdebrpm)。

总结

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

目录
相关文章
|
存储 机器学习/深度学习 SQL
图解大数据 | 分布式平台Hadoop与Map-Reduce详解
Hadoop是最基础和场景的开源分布式计算平台,ShowMeAI在本节内容中给大家讲解Hadoop相关知识。
793 0
图解大数据 | 分布式平台Hadoop与Map-Reduce详解
基于SIR模型的疫情发展趋势预测算法matlab仿真
该程序基于SIR模型预测疫情发展趋势,通过MATLAB 2022a版实现病例增长拟合分析,比较疫情防控力度。使用SIR微分方程模型拟合疫情发展过程,优化参数并求解微分方程组以预测易感者(S)、感染者(I)和移除者(R)的数量变化。![]该模型将总人群分为S、I、R三部分,通过解析或数值求解微分方程组预测疫情趋势。
|
消息中间件 Java 数据处理
揭秘Apache Flink的Exactly-Once神技:如何在数据流海中确保每条信息精准无误,不丢不重?
【8月更文挑战第26天】Apache Flink 是一款先进的流处理框架,其核心特性 Exactly-Once 语义保证了数据处理的精准无误。尤其在金融及电商等高要求场景下,该特性极为关键。本文深入解析 Flink 如何实现 Exactly-Once 语义:通过状态管理确保中间结果可靠存储;利用一致的检查点机制定期保存状态快照;以及通过精确的状态恢复避免数据重复处理或丢失。最后,提供一个 Java 示例,展示如何计算用户访问次数,并确保 Exactly-Once 语义的应用。
419 0
|
缓存 Oracle Java
JDK8到JDK22版本升级的新特性问题之在JDK17中,日志的刷新如何操作
JDK8到JDK22版本升级的新特性问题之在JDK17中,日志的刷新如何操作
|
算法 调度
【完全复现】基于改进粒子群算法的微电网多目标优化调度
该文档描述了一个使用改进粒子群算法实现的微电网多目标优化调度的Matlab程序。该模型旨在最小化运行成本和环境保护成本,将多目标问题通过权值转换为单目标问题解决。程序中定义了决策变量,如柴油发电机、微型燃气轮机、联络线和储能的输出,并使用全局变量处理电负荷、风力和光伏功率等数据。算法参数包括最大迭代次数和种群大小。代码调用了`PSOFUN`函数来执行优化计算,并展示了优化结果的图表。
|
SQL 分布式计算 DataWorks
MaxCompute产品使用合集之如何识别并执行某个字段的 SQL 语句,并输出结果
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
287 2
|
消息中间件 Java Kafka
Spring 事务的独门绝技:钩子函数的使用技巧
经过前面对Spring AOP、事务的总结,我们已经对它们有了一个比较感性的认知了。今天,我继续安利一个独门绝技:Spring 事务的钩子函数。单纯的讲技术可能比较枯燥乏味。接下来,我将以一个实际的案例来描述Spring事务钩子函数的正确使用姿势。
Spring 事务的独门绝技:钩子函数的使用技巧
|
域名解析 弹性计算 Linux
阿里云服务器搭建从0开始部署
阿里云服务器搭建从0开始部署,使用阿里云服务器快速搭建网站教程,先为云服务器安装宝塔面板,然后在宝塔面板上新建站点,阿里云服务器网以搭建WordPress网站博客为例,来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程
676 1
|
Ubuntu Linux Android开发
百度搜索:【蓝易云】 Termux安装完整版Linux(Ubuntu)详细步骤
Termux是一款在Android系统上运行的终端模拟器,可以让用户在手机上运行Linux命令行工具和应用程序。本文将介绍如何在Termux中安装完整版Linux(Ubuntu)。
511 1
|
缓存 前端开发 JavaScript
Vite 打包优化:全面解析与实践
Vite 作为新一代前端构建工具,以其快速开发体验和高效打包能力著称。然而,在实际项目开发中,为了进一步提升性能和用户体验,我们仍需对 Vite 打包进行优化。本文将深入探讨 Vite 打包优化策略,涵盖代码拆分、资源压缩、缓存利用、构建配置等多个方面,并提供实践案例和最佳实践建议,帮助开发者充分释放 Vite 的潜力。
2810 1