Java 13 来袭,最新最全新特性解读

GitHub 8.5k Star 的Java工程师成神之路 ,不来了解一下吗?html

GitHub 8.52k Star 的Java工程师成神之路 ,真的不来了解一下吗?java

GitHub 8.5k Star 的Java工程师成神之路 ,真的肯定不来了解一下吗?git

2017年8月,JCP执行委员会提出将Java的发布频率改成每六个月一次,新的发布周期严格遵循时间点,将在每一年的3月份和9月份发布。github

目前,JDK官网上已经能够看到JDK 13的进展,最新版的JDK 13将于2019年9月17日发布。markdown

目前,JDK13处于Release-Candidate Phase(发布候选阶段),将于9月17日正式发布。目前该版本包含的特性已经所有固定,主要包含如下五个:oop

JEP 350,Dynamic CDS Archives编码

JEP 351,ZGC: Uncommit Unused Memoryspa

JEP 353,Reimplement the Legacy Socket API操作系统

JEP 354: Switch Expressions (Preview).net

JEP 355,Text Blocks (Preview)

下面来逐一介绍下这五个重要的特性。

Dynamic CDS Archives

这一特性是在JEP310:Application Class-Data Sharing基础上扩展而来的,Dynamic CDS Archives中的CDS指的就是Class-Data Sharing。

那么,这个JEP310是个啥东西呢?

咱们知道在同一个物理机/虚拟机上启动多个JVM时,若是每一个虚拟机都单独装载本身须要的全部类,启动成本和内存占用是比较高的。因此Java团队引入了CDS的概念,经过把一些核心类在每一个JVM间共享,每一个JVM只须要装载本身的应用类,启动时间减小了,另外核心类是共享的,因此JVM的内存占用也减小了。

CDS 只能做用于 Boot Class Loader 加载的类,不能做用于 App Class Loader 或者自定义的 Class Loader 加载的类。

在 Java 10 中,则将 CDS 扩展为 AppCDS,顾名思义,AppCDS 不止可以做用于 Boot Class Loader了,App Class Loader 和自定义的 Class Loader 也都可以起做用,大大加大了 CDS 的适用范围。也就说开发自定义的类也能够装载给多个JVM共享了。

Java 10中包含的JEP310的经过跨不一样Java进程共享公共类元数据来减小了内存占用和改进了启动时间。

可是,JEP310中,使用AppCDS的过程仍是比较复杂的,须要有三个步骤:

一、决定要 Dump 哪些 Class
二、将类的内存 Dump 到归档文件中
三、使用 Dump 出来的归档文件加快应用启动速度
复制代码

这一次的JDK 13中的JEP 350 ,在JEP310的基础上,又作了一些扩展。容许在Java应用程序执行结束时动态归档类,归档类将包括默认的基础层 CDS(class data-sharing)存档中不存在的全部已加载的应用程序类和库类。

也就是说,在Java 13中再使用AppCDS的时候,就不在须要这么复杂了。

ZGC: Uncommit Unused Memory

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

GC后的内存如何处置,实际上是取决于不一样的垃圾回收器的。由于把内存还给OS,意味着要调整JVM的堆大小,这个过程是比较耗费资源的。

在JDK 11中,Java引入了ZGC,这是一款可伸缩的低延迟垃圾收集器,可是当时只是实验性的。而且,ZGC释放的内存是不会还给操做系统的。

而在Java 13中,JEP 351再次对ZGC作了加强,本次 ZGC 能够将未使用的堆内存返回给操做系统。之因此引入这个特性,是由于现在有不少场景中内存是比较昂贵的资源,在如下状况中,将内存还给操做系统仍是颇有必要的:

  • 一、那些须要根据使用量付费的容器
  • 二、应用程序可能长时间处于空闲状态并与许多其余应用程序共享或竞争资源的环境。
  • 三、应用程序在执行期间可能有很是不一样的堆空间需求。例如,启动期间所需的堆可能大于稍后在稳定状态执行期间所需的堆。

Reimplement the Legacy Socket API

使用易于维护和调试的更简单、更现代的实现替换 java.net.Socket 和 java.net.ServerSocket API。

java.net.Socket和java.net.ServerSocket的实现很是古老,这个JEP为它们引入了一个现代的实现。现代实现是Java 13中的默认实现,可是旧的实现尚未删除,能够经过设置系统属性jdk.net.usePlainSocketImpl来使用它们。

运行一个实例化Socket和ServerSocket的类将显示这个调试输出。这是默认的(新的):

java -XX:+TraceClassLoading JEP353  | grep Socket
[0.033s][info   ][class,load] java.net.Socket source: jrt:/java.base
[0.035s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.035s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketImpl?Lambda$1/0x0000000800b50840 source: java.net.SocketImpl
[0.042s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.042s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base
[0.043s][info   ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base
[0.044s][info   ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.045s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.045s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
复制代码

上面输出的sun.nio.ch.NioSocketImpl就是新提供的实现。

若是使用旧的实现也是能够的(指定参数jdk.net.usePlainSocketImpl):

$ java -Djdk.net.usePlainSocketImpl -XX:+TraceClassLoading JEP353  | grep Socket
[0.037s][info   ][class,load] java.net.Socket source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.043s][info   ][class,load] java.net.SocketImpl?Lambda$1/0x0000000800b50840 source: java.net.SocketImpl
[0.046s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base
[0.047s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.047s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.048s][info   ][class,load] jdk.net.LinuxSocketOptions source: jrt:/jdk.net
[0.048s][info   ][class,load] jdk.net.LinuxSocketOptions?Lambda$2/0x0000000800b51040 source: jdk.net.LinuxSocketOptions
[0.049s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.049s][info   ][class,load] java.net.StandardSocketOptions source: jrt:/java.base
[0.049s][info   ][class,load] java.net.StandardSocketOptions$StdSocketOption source: jrt:/java.base
[0.051s][info   ][class,load] sun.net.ext.ExtendedSocketOptions?Lambda$3/0x0000000800b51440 source: sun.net.ext.ExtendedSocketOptions
[0.057s][info   ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base
[0.057s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
[0.058s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.058s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.058s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
复制代码

上面的结果中,旧的实现java.net.PlainSocketImpl被用到了。

Switch Expressions (Preview)

在JDK 12中引入了Switch表达式做为预览特性。JEP 354修改了这个特性,它引入了yield语句,用于返回值。这意味着,switch表达式(返回值)应该使用yield, switch语句(不返回值)应该使用break。

在之前,咱们想要在switch中返回内容,仍是比较麻烦的,通常语法以下:

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块。

Text Blocks (Preview)

在JDK 12中引入了Raw String Literals特性,但在发布以前就放弃了。这个JEP在引入多行字符串文字(text block)在乎义上是相似的。

text block,文本块,是一个多行字符串文字,它避免了对大多数转义序列的须要,以可预测的方式自动格式化字符串,并在须要时让开发人员控制格式。

咱们之前从外部copy一段文本串到Java中,会被自动转义,若有一段如下字符串:

<html>
  <body>
      <p>Hello, world</p>
  </body>
</html>
复制代码

将其复制到Java的字符串中,会展现成如下内容:

"<html>\n" +
"    <body>\n" +
"        <p>Hello, world</p>\n" +
"    </body>\n" +
"</html>\n";
复制代码

即被自动进行了转义,这样的字符串看起来不是很直观,在JDK 13中,就可使用如下语法了:

"""
<html>
  <body>
      <p>Hello, world</p>
  </body>
</html>
""";
复制代码

使用“”“做为文本块的开始符合结束符,在其中就能够放置多行的字符串,不须要进行任何转义。看起来就十分清爽了。

如常见的SQL语句:

String query = """
    SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
    WHERE `CITY` = 'INDIANAPOLIS'
    ORDER BY `EMP_ID`, `LAST_NAME`;
""";
复制代码

看起来就比较直观,清爽了。

总结

以上,就是JDK13中包含的5个特性,可以改变开发者的编码风格的主要有Text Blocks和Switch Expressions两个新特性,可是这两个特性还处于预览阶段。

并且,JDK13并非LTS(长期支持)版本,若是你正在使用Java 8(LTS)或者Java 11(LTS),暂时能够没必要升级到Java 13.

参考资料: openjdk.java.net/projects/jd… metebalci.com/blog/what-i… www.jianshu.com/p/890196bf5…

相关文章
相关标签/搜索