疾风步行者

V1

2022/08/26阅读:15主题:自定义主题1

Java 13 新特性

Java 13 新特性

Java 13 早在 2019 年 9 月就已经发布,虽然不是长久支持版本,但是也带来了不少新功能。此篇文章写一下部分Java 13的新特性。 Java 13 全部的新特性,请看官网:JDK 13 发行说明 Java各个版本的文档入口:Java平台,标准版文档 Java各个版本下载:https://jdk.java.net/archive/

Switch 表达式 (二次预览)

在Java 12 中对 Switch 进行了一次增强,这次又对Switch进行了增强。 在 Java 13 中,又对 switch 表达式进行了增强,增加了 yield 关键词用于返回值,相比 break ,语义更加明确了。

public static String switchJava13(String month) {
    return switch (month) {
        case "march""april""may":
            yield "春天";
        case "june""july""august":
            yield "夏天";
        case "september""october""november":
            yield "秋天";
        case "december""january""february":
            yield "冬天";
        default:
            yield "month error";
    };
}

动态 CDS 存档

JVM 启动时有一步是需要在内存中加载类,而如果有多个 jar,加载第一个 jar 的速度是最慢的。这就延长了程序的启动时间,为了减少这个时间,Java 10 引入了应用程序类数据共享(CDS)机制,它可以把你想共享的类共享在程序之间,使不同的 Java 进程之间共享这个类来减少这个类占用的空间以及加载速度。不过 Java 10 中使用这个功能的步骤比较繁琐。 而 Java 13 中的 AppCDS,允许 Java 应用在程序执行结束时(如果 JVM 没有崩溃)进行动态存档;存储的内容包括所有加载的应用类型类和使用的类库,这些存储的类库本来并不存在于默认的 CDS 存档中。使用这个功能非常简单,只需要在程序启动时增加启动参数 。

# ArchiveClassesAtExit,程序结束时动态存档
bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
# SharedArchiveFile,使用指定存档启动
bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

ZGC,归还未使用的内存 (实验性)

在 Java 13 之前,ZGC 虽然在清理内存时导致的停顿时间非常少,但是即使内存已经长时间没有使用,ZGC 也不会将内存返还给操作系统,这对那些十分关注内存占用的应用程序非常不友好。 比如:

  • 资源按使用量付费的云上容器环境。
  • 应用虽然长时间闲置,但是占用了内存,导致运行的其他程序内存紧张。

而新增的这个功能,可以让 ZGC 归还长时间没有使用的内存给操作系统,这对某些用户来说十分友好。

重新实现 Socket API

java.net.Socket 和 java.net.ServerSocket 类早在 Java 1.0 时就已经引入了,它们的实现的 Java 代码和 C 语言代码的混合,维护和调试都十分不易;而且这个实现还存在并发问题,有时候排查起来也很困难。 因此,在 Java 13 中引入了新的实现方式,使用了新的实现 NioSocketImpl 来代替老旧的 PlainSocketImpl 实现。虽然功能相同,但是老的方式在当前以及未来几个版本内不会删除,用户随时可以通过 -Djdk.net.usePlainSocketImpl 参数切换回老的实现方式,以兼容意外情况。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Test {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8000)){
            boolean running = true;
            while(running){
                Socket clientSocket = serverSocket.accept();
                //do something with clientSocket
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用 Java 13 运行,通过参数 -XX:+TraceClassLoading 追踪加载的类,日志中可以看到 NioSocketImpl。

➜  develop ./jdk-13.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
[0.699s][info   ][class,loadjava.net.SocketImpl sourcejrt:/java.base
[0.699s][info   ][class,loadjava.net.SocketImpl$$Lambda$173/0x0000000800c37440 sourcejava.net.SocketImpl
[0.702s][info   ][class,loadsun.net.PlatformSocketImpl sourcejrt:/java.base
[0.702s][info   ][class,loadsun.nio.ch.NioSocketImpl sourcejrt:/java.base
[0.713s][info   ][class,loadsun.nio.ch.NioSocketImpl$FileDescriptorCloser sourcejrt:/java.base

但在 Java 12 并不是 NioSocketImpl

➜  develop ./jdk-12.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
[0.665s][info   ][class,loadjava.net.SocketImpl sourcejrt:/java.base
[0.665s][info   ][class,loadjava.net.AbstractPlainSocketImpl sourcejrt:/java.base
[0.665s][info   ][class,loadjava.net.PlainSocketImpl sourcejrt:/java.base
[0.665s][info   ][class,loadjava.net.SocksSocketImpl sourcejrt:/java.base
[0.666s][info   ][class,loadjava.net.AbstractPlainSocketImpl$1 sourcejrt:/java.base

文本块 (预览)

在这之前,如果我们把一个 JSON 赋值给字符串:

String content = "{\n"
    + "    \"upperSummary\": null,\n"
    + "    \"sensitiveTypeList\": null,\n"
    + "    \"gmtModified\": \"2022-08-23 10:50:09\",\n"
    + "    \"lowerGraph\": null,\n"
    + "    \"signature\": \"\",\n"
    + "    \"appName\": \"xxx\",\n"
    + "    \"lowerSummary\": null,\n"
    + "    \"gmtCreate\": \"2022-08-23 10:50:09\",\n"
    + "    \"type\": \"CALL\",\n"
    + "    \"name\": \"xxxx\",\n"
    + "    \"subType\": \"yyy\",\n"
    + "    \"id\": 1,\n"
    + "    \"projectId\": 1,\n"
    + "    \"status\": 1\n"
    + "}";

终于不用写丑陋的长字符串了,从 Java 13 开始你可以使用文本块的方式定义字符串了。

String content2 = """
        {
        "
upperSummary": null,
        "
sensitiveTypeList": null,
        "
gmtModified": "2022-08-23 10:50:09",
        "
lowerGraph": null,
        "
signature": "",
        "
appName": "xxx",
        "
lowerSummary": null,
        "
gmtCreate": "2022-08-23 10:50:09",
        "
type": "CALL",
        "
name": "xxxx",
        "
subType": "yyy",
        "
id": 1,
        "
projectId": 1,
        "
status": 1
    }
                 "
"";

不过这是一个预览功能,如果你要是在 Java 13 中使用需要手动开启预览功能,这个功能在 Java 15 中正式发布。


关注我,给你看更多精彩文章。

分类:

后端

标签:

Java

作者介绍

疾风步行者
V1

还在奔跑的老程序员