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)
下面来逐一介绍下这五个重要的特性。
这一特性是在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的时候,就不在须要这么复杂了。
在讨论这个问题以前,想先问一个问题,JVM的GC释放的内存会还给操做系统吗?
GC后的内存如何处置,实际上是取决于不一样的垃圾回收器的。由于把内存还给OS,意味着要调整JVM的堆大小,这个过程是比较耗费资源的。
在JDK 11中,Java引入了ZGC,这是一款可伸缩的低延迟垃圾收集器,可是当时只是实验性的。而且,ZGC释放的内存是不会还给操做系统的。
而在Java 13中,JEP 351再次对ZGC作了加强,本次 ZGC 能够将未使用的堆内存返回给操做系统。之因此引入这个特性,是由于现在有不少场景中内存是比较昂贵的资源,在如下状况中,将内存还给操做系统仍是颇有必要的:
使用易于维护和调试的更简单、更现代的实现替换 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被用到了。
在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块。
在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…