本文为【Java新版特性企业级详解】系列文章合集之一,旨在介绍java8-18全部更新功能,本文为第5篇
2019年9月17日,国际知名的OpenJDK开源社区发布了Java编程语言环境的最新版本OpenJDK13。
Features:总共有5个新的JEP(JDK Enhancement Proposals): http://openjdk.java.net/projects/jdk/13/
350:Dynamic CDS Archives动态CDS档案【多个jvm共享资源】。 351:ZGC: Uncommit Unused MemoryZGC:取消使用未使用的内存。 353:Reimplement the Legacy Socket API重新实现旧版套接字API。 354:Switch Expressions (Preview)switch表达式(预览)。 355:Text Blocks (Preview) 文本块。
在JDK 12中引入了Switch表达式作为预览特性。
JDK 13提出了第二个switch表达式预览。JEP 354修改了这个特性,它引入了yield语句,用于返回值。
这意味着,switch表达式(返回值)应该使用yield, switch语句(不返回值)应该使用 break。
在以前,我们想要在switch中返回内容,还是比较麻烦的,一般语法如下:
public static void main(String[] args) { String x = "3"; int i; switch (x) { case "1": i = 1; break; case "2": i = 2; break; default: i = x.length(); break; } System.out.println(i);}在JDK13中使用以下语法:
public static void main(String[] args) { String x = "3"; int i = switch (x) { case "1" -> 1; case "2" -> 2; default -> { yield 3; } }; System.out.println(i);}或者:
public static void main(String[] args) { String x = "3"; int i = switch (x) { case "1": yield 1; case "2": yield 2; default: yield 3; }; System.out.println(i);}在这之后,switch中就多了一个关键字用于跳出switch块了,那就是yield,他用于返回一个值。和return的区别在 于:return会直接跳出当前循环或者方法,而yield只会跳出当前switch块。
在JDK 12中引入了Raw String Literals特性,但在发布之前就放弃了。这个JEP与引入多行字符串文字(text block) 在意义上是类似的。
这条新特性跟 Kotlin 里的文本块是类似的。
在Java中,通常需要使用String类型表达HTML,XML,SQL或JSON等格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码。
这种表达方式难以阅读并且难以维护。
文本块就是指多行字符串,例如一段格式化后的xml、json等。而有了文本块以后,用户不需要转义,Java能自动搞定。
因此,文本块将提高Java程序的可读性和可写性。
定义一段HTML代码:
马士兵教育 将这段代码放入java的String中,会出现如下效果:
String words = "
" + "
" + " 马士兵教育
" + "
" + "";自动将空格换行缩进和特殊符号进行了转义,但是在JDK13中可以使用这样的语法了:
String words = """ 马士兵教育 """;使用"""作为文本块的开始符和结束符,在其中就可以放置多行的字符串,不需要进行任何转义。看起来就十分清爽了。
如常见的SQL语句:
String newQuery = """ select empno,ename,sal,deptno from emp where deptno in (40,50,60) order by deptno asc """;详细说明:
"""line1line2line3"""以下是错误格式的文本块:
String a = """"""; // 开始分隔符后没有行终止符String b = """ """; // 开始分隔符后没有行终止符String c = """ "; // 没有结束分隔符String d = """abc \ def"""; // 含有未转义的反斜线(请参阅下面的转义处理)在运行时,文本块将被实例化为String的实例,就像字符串一样。从文本块派生的String实例与从字符串派生的实例是无法区分的。具有相同内容的两个文本块将引用相同的String实例,就像字符串一样。
编译器在编译时,会删除多余的空格。
下面这段代码中,我们用.来表示我们代码中的的空格,而这些位置的空格就是多余的。
String html = """............................ .............. Hello, world
.............. ............................""";多余的空格还会出现在每一行的结尾,特别是当你从其他地方复制过来时,更容易出现这种情况,比如下面的代码:
String html = """............................... .............. Hello, world
.................. ................................""";每行文字后面的空格。编译器会自动帮助我们去掉。但是开头部分的空格和结束的""";前面的空格数有关, """;前面有几个空格,就会自动帮助我们去掉每一行前面的几个空格
这些多余的空格对于程序员来说是看不到的,但是他又是实际存在的,所以如果编译器不做处理,可能会导致程序员看到的两个文本块内容是一样的,但是这两个文本块却因为存在这种多余的空格而导致差异,比如哈希值不相等。
注意:转义字符相关使用
允许开发人员使用 ,\f 和\r 来进行字符串的垂直格式化,使用 \b和 进行水平格式化。比如下面的代码是合法的:
String html = """
Hello, world
""";请注意,在文本块内自由使用"是合法的。例如:
String story = """ "When I use a word," Humpty Dumpty said, in rather a scornful tone, "it means just what I choose it to mean - neither more nor less." "The question is," said Alice, "whether you can make words mean so many different things." "The question is," said Humpty Dumpty, "which is to be master - that's all." """;但是,三个"字符的序列需要进行转义至少一个"以避免模仿结束分隔符:
String code = """ String text = \""" A text block inside a text block \"""; """;注意:文本块连接
可以在任何可以使用字符串的地方使用文本块。例如,文本块和字符串可以相互连接:
String code = "public void print(Object o) {" + """ System.out.println(Objects.toString(o)); } """;但是,涉及文本块的连接可能变得相当笨重。以下面文本块为基础:
String code = """ public void print(Object o) { System.out.println(Objects.toString(o)); }""";假设我们想把上面的Object改为来自某一变量,我们可能会这么写:
String code = """ public void print(""" + type + """ o) { System.out.println(Objects.toString(o)); } """;可以发现这种写法可读性是非常差的,更简洁的替代方法是使用String::replace或String::format,比如:
String code = """ public void print($type o) { System.out.println(Objects.toString(o)); } """.replace("$type", type); String code = String.format(""" public void print(%s o) { System.out.println(Objects.toString(o)); } """, type);另一个方法是使用String :: formatted,这是一个新方法,比如:
String source = """ public void print(%s object) { System.out.println(Objects.toString(object)); } """.formatted(type);在Java 13中,JEP 351再次对ZGC做了增强,将没有使用的堆内存归还给操作系统。当前的ZGC不能把内存归还给操作系统,即使是那些很久都没有使用的内存,也只进不出。这种行为并不是对任何应用和环境都是友好的,尤其是那些内存占用敏感的服务,例如:
细节说明:
ZGC的堆由若干个Region组成,每个Region被称之为ZPage。每个Zpage与数量可变的已提交内存相关联。当ZGC压缩堆的时候,ZPage就会释放,然后进入page cache,即ZPageCache。这些在page cache中的ZPage集合就表示没有使用部分的堆,这部分内存应该被归还给操作系统。
回收内存可以简单的通过从page cache中逐出若干个选好的ZPage来实现,由于page cache是以LRU(Least recently used,最近最少使用)顺序保存ZPage的,并且按照尺寸(小,中,大)进行隔离,因此逐出ZPage机制和回收内存相对简单了很多,主要挑战是设计关于何时从pagecache中逐出ZPage的策略。
一个简单的策略就是设定一个超时或者延迟值,表示ZPage被驱逐前,能在page cache中驻留多长时间。这个超时时间会有一个合理的默认值,也可以通过JVM参数覆盖它。Shenandoah GC用了一个类型的策略,默认超时时间是5分钟,可以通过参数-XX:ShenandoahUncommitDelay = milliseconds覆盖默认值。
像上面这样的策略可能会运作得相当好。但是,用户还可以设想更复杂的策略:不需要添加任何新的命令行选项。例如,基于GC频率或某些其他数据找到合适超时值的启发式算法。JDK13将使用哪种具体策略目前尚未确定。可能最初只提供一个简单的超时策略,使用-XX:ZUncommitDelay = seconds选项,以后的版本会添加更复杂、更智能的策略(如果可以的话)。
uncommit能力默认是开启的,但是无论指定何种策略,ZGC都不能把堆内存降到低于Xms。这就意味着,如果Xmx和Xms相等的话,这个能力就失效了。-XX:-ZUncommit这个参数也能让这个内存管理能力失效。
在JAVA应用程序在程序执行结束时动态归档类. 归档的类将包括默认基层CDS归档中不存在的所有已加载应用程序类和类库。
CDS,是java 12的特性了,可以让不同 Java 进程之间共享一份类元数据,减少内存占用,它还能加快应用的启动速度。而JDK13的这个特性支持在Java application执行之后进行动态archive。存档类将包括默认的基础层CDS存档中不存在的所有已加载的应用程序和库类。
也就是说,在Java 13中再使用AppCDS的时候,就不再需要这么复杂了。该提案处于目标阶段,旨在提高AppCDS的可用性,并消除用户进行运行时创建每个应用程序的类列表的需要。
# JVM退出时动态创建共享归档文件:导出jsajava -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello# 用动态创建的共享归档文件运行应用:使用jsajava -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloJAVA13 这次对CDS增强的目的:
在JDK13中做的增强,可以只开启命令行选项完成上述过程,在程序运行的时候,动态评估哪些类需要归档,同时支持内置的类加载器和用户定义的类加载器。
在第一次程序执行完成后,会自动的将类进行归档,后续启动项目的时候也无需指定要使用哪些归档,整个过程看起来更加透明。
增加项
移除项
废弃项
Java专业人士 原创文章
请【关注】【点赞】【收藏】
如需转载,请回复说明
| 留言与评论(共有 0 条评论) “” |