switch优化更新

jdk11以及之前的版本:
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;
}
JDK12版本
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);
 }
JDK13版本
static void howMany(int k) {
    System.out.println(
        switch (k) {
            case  1 -> "one"
            case  2 -> "two"
            default -> "many"
        }
    );
}

//以前
int i;
switch (x) {
    case "1":
        i=1;
        break;
    case "2":
        i=2;
        break;
    default:
        i = x.length();
        break;
}


//JDK13
int i = switch (x) {
    case "1" -> 1;
    case "2" -> 2;
    default -> {
        int len = args[1].length();
        yield len;
    }
};
//或者
int i = switch (x) {
    case "1": yield 1;
    case "2": yield 2;
    default: {
        int len = args[1].length();
        yield len;
    }
};
在这之后,switch中就多了一个关键字用于跳出switch块了,那就是yield,他用于返回一个值。和return的区别在于:return会直接跳出当前循环或者方法,而yield只会跳出当前switch块。

文本块升级

JDK13之前
String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";
JDK13优化
String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
JDK13之前
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";
JDK13
String query = """    
                SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
                WHERE `CITY` = 'INDIANAPOLIS'
                ORDER BY `EMP_ID`, `LAST_NAME`;
               """;
解释
"""
line 1
line 2
line 3
"""
相当于
"line 1\nline 2\nline 3\n"

动态CDS档案

这一特性是在JEP310:Application Class-Data Sharing基础上扩展而来的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。
这个JEP310是个啥东西呢?
在同一个物理机/虚拟机上启动多个JVM时,如果每个虚拟机都单独装载自己需要的所有类,启动成本和内存占用是比较高的。所以Java团队引入了CDS的概念,通过把一些核心类在每个JVM间共享,每个JVM只需要装载自己的应用类,启动时间减少了,另外核心类是共享的,所以JVM的内存占用也减少了。
在 Java 10 中,则将 CDS 扩展为 AppCDS,顾名思义,AppCDS 不止能够作用于 Boot Class Loader了,App Class Loader 和自定义的 Class Loader 也都能够起作用,大大加大了 CDS 的适用范围。也就说开发自定义的类也可以装载给多个JVM共享了。
CDS 只能作用于 Boot Class Loader 加载的类,不能作用于 App Class Loader 或者自定义的 Class Loader 加载的类
Java 10中包含的JEP310的通过跨不同Java进程共享公共类元数据来减少了内存占用和改进了启动时间。但是,JEP310中,使用AppCDS的过程还是比较复杂的,需要有三个步骤:
  1. 决定要 Dump 哪些 Class
  2. 将类的内存 Dump 到归档文件中
  3. 使用 Dump 出来的归档文件加快应用启动速度
这一次的JDK 13中的JEP 350 ,在JEP310的基础上,又做了一些扩展。允许在Java应用程序执行结束时动态归档类,归档类将包括默认的基础层 CDS(class data-sharing)存档中不存在的所有已加载的应用程序类和库类。也就是说,在Java 13中再使用AppCDS的时候,就不在需要这么复杂了。

提高应用程序类 - 数据共享(AppCDS)的可用性。消除了用户进行试运行以创建每个应用程序的类列表的需要。
-Xshare:dump
使用类列表由该选项启用的静态归档应继续工作。这包括内置类加载器和用户定义的类加载器的类。

取消使用未使用的内存

在讨论这个问题之前,想先问一个问题,JVM的GC释放的内存会还给操作系统吗?

GC后的内存如何处置,其实是取决于不同的垃圾回收器的。因为把内存还给OS,意味着要调整JVM的堆大小,这个过程是比较耗费资源的。
  1. 那些需要根据使用量付费的容器
  2. 应用程序在执行期间可能有非常不同的堆空间需求。例如,启动期间所需的堆可能大于稍后在稳定状态执行期间所需的堆。
  3. 应用程序可能长时间处于空闲状态并与许多其他应用程序共享或竞争资源的环境。
在JDK 11中,Java引入了ZGC,这是一款可伸缩的低延迟垃圾收集器,但是当时只是实验性的。并且,ZGC释放的内存是不会还给操作系统的。
而在Java 13中,JEP 351再次对ZGC做了增强,本次 ZGC 可以将未使用的堆内存返回给操作系统。之所以引入这个特性,是因为如今有很多场景中内存是比较昂贵的资源,在以下情况中,将内存还给操作系统还是很有必要的:增强ZGC以将未使用的堆内存返回给操作系统。

ZGC目前没有取消提交并将内存返回给操作系统,即使该内存长时间未使用。对于所有类型的应用程序和环境,此行为并非最佳,尤其是那些需要关注内存占用的应用程序和环境 例如:通过使用支付资源的容器环境。应用程序可能长时间处于空闲状态并与许多其他应用程序共享或竞争资源的环境。应用程序在执行期间可能具有非常不同的堆空间要求。 例如,启动期间所需的堆可能大于稳态执行期间稍后所需的堆。HotSpot中的其他垃圾收集器,如G1和Shenandoah,今天提供了这种功能,某些类别的用户发现它非常有用。将此功能添加到ZGC将受到同一组用户的欢迎。

重新实现旧版套接字API  

使用易于维护和调试的更简单、更现代的实现替换 java.net.Socket 和 java.net.ServerSocket API。
java.net.Socket和java.net.ServerSocket的实现非常古老,这个JEP为它们引入了一个现代的实现。现代实现是Java 13中的默认实现,但是旧的实现还没有删除,可以通过设置系统属性jdk.net.usePlainSocketImpl来使用它们。
运行一个实例化Socket和ServerSocket的类将显示这个调试输出。这是默认的(新的):


如果使用旧的实现也是可以的(指定参数jdk.net.usePlainSocketImpl):

使用更简单,更现代的实现替换java.net.Socket和java.net.ServerSocketAPI 使用的底层实现,易于维护和调试。新的实现很容易适应用户模式线程,也就是光纤,目前正在Project Loom中进行探索
在java.net.Socket和java.net.ServerSocketAPI,以及它们的底层实现,可以追溯到JDK 1.0。实现是遗留Java和C代码的混合,维护和调试很痛苦。该实现使用线程堆栈作为I/O缓冲区,这种方法需要多次增加默认线程堆栈大小。该实现使用本机数据结构来支持异步关闭,这是多年来微妙可靠性和移植问题的根源。该实现还有几个并发问题,需要进行大修才能正确解决。在未来的光纤世界环境中,而不是在本机方法中阻塞线程,当前的实现不适用于目的。

FileSystems.newFileSystem新方法

核心库/ java.nio中添加了FileSystems.newFileSystem(Path,Map <String,?>)方法
 添加了三种新方法java.nio.file.FileSystems,以便更轻松地使用将文件内容视为文件系统的文件系统提供程序。
1、newFileSystem(Path)
2、newFileSystem(Path, Map<String, ?>)
3、newFileSystem(Path, Map<String, ?>, ClassLoader)
    添加为newFileSystem(Path, Map<String, ?>) 已使用现有2-arg newFileSystem(Path, ClassLoader)并指定类加载器的代码创建源(但不是二进制)兼容性问题。null.例如,由于引用newFileSystem不明确,因此无法编译以下内容:FileSystem fs = FileSystems.newFileSystem(path, null);
为了避免模糊引用,需要修改此代码以将第二个参数强制转换为java.lang.ClassLoader。

nio新方法

核心库/ java.nio中新的java.nio.ByteBuffer批量获取/放置方法转移字节而不考虑缓冲区位置。
java.nio.ByteBufferjava.nio现在,其他缓冲区类型定义绝对批量get和put传输连续字节序列的方法,而不考虑或影响缓冲区位置。

核心库/ java.time

新日本时代名称Reiwa,此更新中添加了代表新Reiwa时代的实例。与其他时代不同,这个时代没有公共领域。它可以通过调用JapaneseEra.of(3)或获得JapaneseEra.valueOf("Reiwa")。JDK13及更高版本将有一个新的公共领域来代表这个时代。
NewEra从2019年5月1日开始的日本时代的占位符名称“ ”已被新的官方名称取代。依赖占位符名称(请参阅JDK-8202088)获
取新时代单例(JapaneseEra.valueOf("NewEra"))的应用程序将不再起作用。请参阅JDK-8205432

核心库/ java.util中:I18N

支持Unicode 12.1,此版本将Unicode支持升级到12.1,其中包括以下内容:
java.lang.Character支持12.1级的Unicode字符数据库,其中12.0从11.0开始增加554个字符,总共137,928个字符。这些新增内容包括4个新脚本,总共150个脚本,以及61个新的表情符号字符。U+32FF SQUARE ERA NAME REIWA从12.0开始,12.1只添加一个字符。java.text.Bidi和java.text.Normalizer类分别支持12.0级的Unicode标准附件,#9和#15。java.util.regexpackage支持基于12.0级Unicode标准附件#29的扩展字形集群。

热点/ GC

10.1 JEP 351 ZGC取消提交未使用的存储器
10.2 添加了-XXSoftMaxHeapSize标志
10.3 ZGC支持的最大堆大小从4TB增加到16TB

安全库/ java.security

 11.1 该com.sun.security.crl.readtimeout系统属性设置为CRL检索的最大读取超时,单位为秒。如果尚未设置该属性,或者其值为负,则将其设置为默认值15秒。值0表示无限超时。
 11.2 新的keytool -showinfo -tls用于显示TLS配置信息的命令keytool -showinfo -tls添加了一个显示TLS配置信息的新命令。
 11.3 SunMSCAPI提供程序现在支持以下一代加密(CNG)格式读取私钥。这意味着CNG格式的RSA和EC密钥可从Windows密钥库加载,例如“Windows-MY”。与EC(签名算法SHA1withECDSA,SHA256withECDSA等等)也支持。

删除功能

 12.1 核心库/java.net中,不再支持Pre-JDK 1.4 SocketImpl实现java.net.SocketImpl此版本已删除对为JavaSE1.3及更早版本编译的自定义实现的支持。此更改对SocketImpl为Java SE 1.4(2002年发布)或更新版本编译的实现没有影响。    
12.2 核心库/java.lang中,删除运行时跟踪方法,过时的方法traceInstructions(boolean),并traceMethodCalls(boolean)已经从删除java.lang.Runtime类。这些方法对许多版本都不起作用,它们的预期功能由Java虚拟机工具接口(JVMTI)提供。


以上,就是JDK13中包含的特性,能够改变开发者的编码风格的主要有Text Blocks和Switch Expressions两个新特性,但是这两个特性还处于预览阶段。而且,JDK13并不是LTS(长期支持)版本,如果你正在使用Java 8(LTS)或者Java 11(LTS),暂时可以不必升级到Java 13.