点击上方 "程序员小乐"关注, 星标或置顶一起成长

每天凌晨00点00分, 第一时间与你相约

每日英文

You can't just sit there and wait for life to come to you. You have to go get it. 

你不能无所事事的坐等人生带给你一切,你必须得自己努力争取。

每日掏心

生活总会给你另一个机会,这个机会叫明天。生活没有过去,也没有曾经,不管什么事只要过去了,就会慢慢忘掉。

来自:覃佑桦 | 责编:乐乐

链接:techgeeknext.com/java/java14-features

Java 14 新特性速览,看了都说好!_Java开发程序员小乐(ID:study_tech) 第 844 次推文   图片来自百度

往日回顾:手把手教你如何搭建一款自己的私有百度网盘?

     

   正文   

Java14发布了!

2020年3月17日,世界上使用最多的编程语言和应用开发平台JavaSE 14及JDK14发布了。Java14发布了大量JEP(Java增强建议)。新版包含的JEP数量甚至比Java12和13的总和还要多。

Java14主要加入了16个新特性(JEP),包括最新的Java API、JDK Fight Recorder监控等等。完整的新特性列表如下:

1. instanceof模式匹配(预览特性)

2. 非易失性映射字节缓冲(孵化器)

3. 实用的NullPointerException

4. 新switch表达式(标准特性)

5. 打包工具(孵化器)

6. G1中的NUMA内存分配优化

7. JFR事件流

8. Records(预览特性)

9. 弃用Solaris和SPARC端口

10. 移除CMS垃圾回收器

11. 针对macOS的ZGC(实验特性)

12. 针对Windows的ZGC(实验特性)

13. 弃用ParallelScavenge+SerialOld GC组合

14. 移除Pack200工具和API

15. 文本块(第二次预览版)

16. 外存访问API(孵化器)

Oracle为所有开发者和企业用户开放了Java14下载。

1. instanceof模式匹配

instanceof操作符用来检查对象引用是否为指定的Type实例,检查的结果使用boolean返回。Java14对instanceof操作符进行了改进,加入了模式匹配。改进后的instanceof让实现逻辑变得清晰,不用在条件判断后再为对象强制类型转换。

Java14以前

if (obj instanceof String) {
    String str = (String) obj; // 需要再次声明和对象转换
    .. str.contains(..)..
}else{
     str = ....
}	

Java14

if (!(obj instanceof String str)) {
    .. str.contains(..)..// 不必再声明str对象进行强制类型转换
} else {
    .. str....
}

更多示例:

if (obj instanceof String str && str.length() > 5) {.. str.contains(..)..}

if (obj instanceof String str || str.length() > 5) {.. str.contains(..)..}

注意:只有object不为null时instanceof才会匹配并把结果分配给str。使用instanceof模式匹配可以减少Java程序中进行强制转换。

2. 非易失性映射字节缓冲(孵化器)

简要地说,JDK1.4开始Java NIO File API就出现了。

FileChannel MappedByteBuffer 该API将部分文件数据加载到虚拟内存中,然后引入了Path特性。Path是一个接口。使用Java NIO开发时,可以用Path替代java.io.File表示文件或目录。 

现在,Java 14对MappedByteBuffer进行了改进,将部分文件数据加载到非易失性存储器(NVM)中。NVM非易失性存储是指类似ROM(只读存储器)、闪存、硬盘等存储器,即使关闭电源数据也不会丢失。易失性存储器比如RAM,如果关闭电源则无法保存数据。API唯一的变化是加入了一个新枚举供FileChannel客户端使用。表示请求映射位于NVM支持的文件系统而非传统文件系统。

风险与假设

该特性允许通过ByteBuffer将NVM作为堆外资源进行管理。与此相关的增强功能JDK-8153111正在研究将NVM用于堆数据。可能还会考虑使用NVM存储JVM元数据。不同的NVM管理模式一起使用时也许不兼容,也可能仅仅是不合适。API建议只支持最大2GB映射空间。必要时可以改动实现策略,使其符合,JDK-8180628以突破此限制。

3. 实用的NullPointerException

Java14对JVM生成的NullPointerException异常信息进行了改进。程序提前终止时,新特性将为开发者和技术支持人员提供有用的信息。由于NPE几乎可以出现在程序中的任何位置,尝试捕获它们并从中恢复通常不太可行。开发人员只能靠JVM确认NPE实际的发生时间。例如,假设下面代码抛出一个NPE:

a.i = 99;

JVM会输出导致NPE的方法、文件名和行号:

Exception in thread "main" java.lang.NullPointerException
                            at Prog.main(Prog.java:5)

现在假设下面代码抛出一个NPE:

a.b.c.i = 99;

仅通过文件名和行号并不能精确指出究竟哪个变量为null。是变量a、变量b还是变量c?

JDK14 JEP改进了异常信息,按照下面的方式抛出该异常,能够确切知道哪个变量为null。

Exception in thread "main" java.lang.NullPointerException:
        Cannot read field 'c' because 'a.b' is null.
    at Prog.main(Prog.java:5)

与此同时也带来一些风险。null详细信息可能包含源代码中的变量名。暴露这些信息可能会带来安全风险。

4. 新switch表达式(标准特性)

Java14扩展了switch语句的功能,可以把switch作为表达式使用。支持箭头(->)操作符生成或返回值。该特性在JDK12和JDK13中是预览功能。

例1Java14以前

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

Java14

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

例2Java14以前   

int numLetters;
switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        numLetters = 6;
        break;
    case TUESDAY:
        numLetters = 7;
        break;
    case THURSDAY:
    case SATURDAY:
        numLetters = 8;
        break;
    case WEDNESDAY:
        numLetters = 9;
        break;
    default:
        throw new IllegalStateException("Wat: " + day);
}

Java14

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

更多示例   

// 箭头标签
static void grade(int g) {
    System.out.println(
        switch (g) {
            case  1 -> "A";
            case  2 -> "B";
            default -> "C";
        }
    );
}
------------------------------------------
// 生成值-引入新的yield用法
int j = switch (day) {
    case MONDAY  -> 0;
    case TUESDAY -> 1;
    default      -> {
        int d = day.toString().length();
        int result = f(d);
        yield result;
    }
};

5. 打包工具(孵化器)

该特性是一种能够简化安装过流程的打包功能,能解决应用所需的各种依赖项。有时仅提供一个JAR文件是不够的,还需要提供原生安装包。打包工具还可以作为其它技术的补充。

jpackage工具把Java应用打包成平台特定格式的包,其中包含应用所有的依赖项。即一组普通JAR文件或模块的集合。支持的包格式:

1. Linux:deb和rpm

2. macOS:pkg和dmg

3. Windows:MSI和EXE

6. G1中的NUMA内存分配优化

非一致性内存访问(NUMA)是一种将微处理器集群配置为多处理系统的方式,因此可以在本地共享内存、提高性能并扩展系统能力。Java14实现了NUMA内存分配优化,提升G1在大型计算机上表现。G1中的堆是一组固定大小区域。虽然指定-XX:+UseLargePages选项可以使用大页面,多个区域可以组成一个物理页面,但是一个区域通常是一组物理页面。如果指定+XX:+UseNUMA选项,初始化JVM时上述将把区域平均分布在所有可用NUMA节点上。

7. JFR事件流

Java14提供了一个新的API,JDK Flight Recorder(JFR)可以通过它持续监视进程内与进程外部应用程序。

使用非Stream方式记录相同的事件集,开销可能甚至小于1%。事件流将与非Stream方式同时执行。

jdk.jfr.consumer包位于 jdk.jfr模块中,扩展了异步订阅事件的功能。

8.Record(预览特性)

这是JDK14中一个预览功能。使用record精简类声明代码。

定义一个数据类需要编写很多低效重复的模板代码:构造函数、accessor、equals()、hashCode()、toString()等。Java计划使用record精简这些重复代码。

示例:

Java14以前:   

final class Point {
    public final int x;
    public final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // equals、hashCode、toString方法
    // 其它什么也没干

Java14使用record   

record Point(int x, int y) { }

使用record的局限:

· record不能继承其它类,除了描述状态的私有final字段外不能声明其它字段实例。

· record默认为final且不能声明为abstract。这意味着record API完全由状态定定义,不能被其它类或者其它record修改。

· record组件隐式定义为final。

9. 弃用Solaris和SPARC端口

· Java14弃用了Solaris/SPARC、Solaris/x64和Linux/SPARC端口,未来可能将它们移除。

· 取消对这些端口的支持,能让OpenJDK社区的贡献者加速开发新功能,推动平台向前发展。

构建配置变化下面尝试配置Solaris/SPARC   

$ bash ./configure
...
checking compilation type... native
configure: error: The Solaris and SPARC ports are deprecated and may be removed in a future release.\
Use --enable-deprecated-ports=yes to suppress this error.
configure exiting with result code 1
$

设置--enable-deprecated-port=yes构建选项可以解决错误继续配置。   

$ bash ./configure --enable-deprecated-ports=yes
...
checking compilation type... native
configure: WARNING: The Solaris and SPARC ports are deprecated and may be removed in a future release.
...
Build performance summary:
* Cores to use:   32
* Memory limit:   96601 MB

构建Solaris和SPARC版本会报告错误或警告,包括Solaris/SPARC、Solaris/x64、Linux/SPARC。

10. 移除CMS垃圾回收器

Java14删除了CMS垃圾收集器。

不仅停用CMS编译,从源代码中删除了gc/cms目录中的内容,而且删除了仅限CMS的选项。

使用-XX:+UseConcMarkSweepGC选项启用CMS时会提示以下警告:   

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; \
support was removed in <version>

虚拟机会继续使用默认垃圾收集器。

11. JEP 364:针对macOS的ZGC(实验特性)

JEP 364实际上和JEP3 65一样。JEP 364针对MacOS提供了ZGC垃圾收集器。它将ZGC垃圾收集器移植到了macOS。正如JEP351中的描述,该JEP的功能还包括使用收集器释放未使用的设备内存。自Java13开始就支持此功能。ZGC的macOS实现包含两个部分:

1. 在macOS上支持多重映射(multi-mapping)内存。

2. ZGC支持不连续预留内存。

12. JEP 365:针对Windows的ZGC(实验特性)

JEP 365实际上和JEP 364一样。JEP 365针对Windows提供了ZGC垃圾收集器支持。

大多数ZGC代码都与平台无关,不需要为Windows修改。由于早期版本没有预留内存必须的API,因此不支持Windows 10和Windows Server 1803之前的版本。

ZGC的Windows实现进行了以下工作:

1. 支持多重映射内存

由于ZGC使用着色指针(colored pointer),因此需要多重映射支持,以便可以从进程地址空间中的多个位置访问相同的物理内存。Windows内存使用分页文件为物理内存提供了一个标识(句柄),与映射的虚拟内存地址无关。ZGC使用该标识可以将相同的物理内存映射到多个地址。

2. 支持将内存映射到预留地址空间,基于分页文件技术。

Windows内存管理API没有POSIX mmap/munmap灵活,当涉及到将文件备份内存映射到之前预留的空间时尤其如此。因此,ZGC使用了Windows地址占位符概念。在Windows 10 V1803和Windows Server中引入了占位符概念。ZGC不支持Windows其它早期版本。

3. 支持堆内存任意区域映射与取消映射操作。

ZGC堆的布局要求支持任意粒度的内存映射和取消映射,以及堆页面动态调整大小与重新调整。此要求与Windows地址空间占位符结合使用时,需要特别注意,因为占位符必须由程序显式拆分/合并,而不是由操作系统自动拆分/合并(与Linux一样)。

4. 支持堆内存任意区域提交和撤销提交操作。

ZGC能在Java程序运行时动态提交和撤销物理内存。为了支持这些操作,物理内存被分为多个分页文件片段。每个片段都对应一个ZGC堆单元,可以独立提交和撤销。

13. JEP 366:弃用ParallelScavenge+SerialOld GC组合

JEP366包含垃圾收集器,它的目标是弃用Parallel Scavenge和Serial Old垃圾收集算法的组合。除了弃用-XX:+UseParallelGC-XX :- UseParallelOldGC组合之外,-XX:UseParallelOld GC选项也被弃用,因为它的作用是取消老年代并行GC,支持老年代串行GC。因此,任何与UseUseParallelOldGC选项有关的用法都会输出警告。

14. JEP 367:移除Pack200工具和API

Pack 200是JavaSE 5.0中JSR 200实现的JAR文件压缩方案。

Java14从java.util.jar包中移除了pack200和unpack200工具以及pack200 API。这些工具和API在JavaSE 11中已废弃,会在随后的版本中移除。该JEP最终会从JDK主版本中移除3种类型。即之前标记 @Deprecated(forRemoval = true) 注解的基础模块:

· java.util.jar.Pack200

· java.util.jar.Pack200.Packer

· java.util.jar.Pack200.Unpacker

15. JEP 368:文本块(第二次预览版)

在Java中,想要把HTML、XML、SQL或JSON代码片段嵌入到代码中通常难以阅读和保留。并且为了克服此问题,Java14 引入了文本块(Text Block)。

文本块包含零个或多个字符,这些字符由开始分隔符和结束分隔符包围。

没有使用文本块HTML示例   

String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

文本块的开始分隔符以三个双引号(""")开始,可以接零个或多个空格,最后是一个换行符。开始分隔符换行后面接着是文本块的内容。

结束分隔符同样是三个双引号。文本块内容在三个双引号之前结束。

与String不同,文本块中可以直接使用双引号。当然也可以使用\" 但不是必需的。选择宽分隔符(""")的好处是可以直接使用"不需要转义,而且能从视觉上把文本块与String进行区分。

文本块是多行String文本。使用文本块能避免大多数转义的情况,支持自动格式化字符串,并且在必要时开发者能自行格式化字符串。

使用文本块的HTML示例   

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;

2019年初,JEP 355提议把文本块功能作为JEP 326(原始字符串字)的后续改进,随后该提议被撤回。

2019年中,JDK13把文本块作为预览功能加入,接着Java14加入了两个新的转义符。

其一,用\表示换行。其二,是用/s表示一个空格。

换行符示例:

// 不使用文本块
String literal = "two escape sequences first is for newlines " +
"and, second is to signify white space " +
"or single space.";

// 使用 \ 看起来像这样:
String text = """
                two escape sequences first is for newlines \
                and, second is to signify white space \
                or single space.\
                """;

空白或单空格示例:   

// 在每行的结尾使用 \s,保证每行的长度为6个字节
String colors = """
    aaa\s
    bbb\s
    ccc\s
    """;	

16. JEP 370:外存访问API(孵化器)

许多流行的Java库和程序都支持访问外部存储器,例如Ignite、MapDB、Memcached和Netty的ByteBuf API。这样可以避免垃圾回收(比如维护大型缓存)、跨进程共享内存、通过将文件内存映射进行序列化和反序列化(例如mmap)带来的开销以及引入的不可预测性。然而,Java API没有提供适合的外存访问解决方案。

Java14通过JEP 370引入了高效的Java API,使得Java应用程序能够安全有效地访问Java堆外内存。外部存储API提出了三个重要的抽象:MemorySegment、MemoryAddress和MemoryLayout。

 

Java 14 新特性速览,看了都说好!_Java开发_02

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。

欢迎各位读者加入订阅号程序员小乐技术群,在后台回复“加群”或者“学习”即可。

猜你还想看

阿里、腾讯、百度、华为、京东最新面试题汇集

5万字长文!SpringBoot 操作 ElasticSearch 详解

关于 MyBatis 我总结了 10 种通用的写法

分布式事务之 RocketMQ 事务消息详解

Java 14 新特性速览,看了都说好!_Java开发_03

关注订阅号「程序员小乐」,收看更多精彩内容

嘿,你在看吗Java 14 新特性速览,看了都说好!_Java开发_04