JDK 14 新特性-你还跟得上吗

版本号

<code>java -version
openjdk version "13" 2019-12-17

OpenJDK Runtime Environment (build 13+33)
OpenJDK 64-Bit Server VM (build 13+33, mixed mode, sharing)/<code>

从version信息可以看出是build 13+33

特性列表

350: Dynamic CDS Archives

JDK5引入了Class-Data Sharing可以用于多个JVM共享class,提升启动速度,最早只支持system classes及serial GC
JDK9对其进行扩展以支持application classes及其他GC算法
java10的新特性JEP 310: Application Class-Data Sharing扩展了JDK5引入的Class-Data Sharing,支持application的Class-Data Sharing并开源出来(以前是commercial feature)
JDK11将-Xshare:off改为默认-Xshare:auto,以更加方便使用CDS特性
JDK12的341: Default CDS Archives即在64-bit平台上编译jdk的时候就默认在${JAVA_HOME}/lib/server目录下生成一份名为classes.jsa的默认archive文件(大概有18M)方便大家使用
JDK13的这个特性支持在Java application执行之后进行动态archive

  • 导出jsa
<code>java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello/<code>
  • 使用jsa
<code>java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello/<code>

351: ZGC: Uncommit Unused Memory

Java12的346: Promptly Return Unused Committed Memory from G1新增了两个参数分别是G1PeriodicGCInterval及G1PeriodicGCSystemLoadThreshold用于GC之后重新调整Java heap size,然后将多余的内存归还给操作系统
Java12的189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)拥有参数-XX:ShenandoahUncommitDelay=<milliseconds>来指定ZPage的page cache的失效时间,然后归还内存


Java13则给ZGC新增归还unused heap memory给操作系统的特性;它新增了几个参数,-XX:ZUncommitDelay=<seconds>用于指定ZPage的page cache的失效时间;ZGC的归还内存默认是开启的,可以使用-XX:-ZUncommit来显式禁用/<seconds>/<milliseconds>

353: Reimplement the Legacy Socket API

本特性替换了java.net.Socket以及java.net.ServerSocket API的底层实现;它使用NioSocketImpl来替换JDK1.0的PlainSocketImpl;如果要继续使用旧版的Socket实现,可以使用-Djdk.net.usePlainSocketImpl参数来切换到旧版本

/Library/Java/JavaVirtualMachines/jdk-13.jdk/Contents/Home/lib/src.zip!/java.base/java/net/SocketImpl.java

<code>public abstract class SocketImpl implements SocketOptions {
private static final boolean USE_PLAINSOCKETIMPL = usePlainSocketImpl();

private static boolean usePlainSocketImpl() {
PrivilegedAction<string> pa = () -> NetProperties.get("jdk.net.usePlainSocketImpl");
String s = AccessController.doPrivileged(pa);
return (s != null) && !s.equalsIgnoreCase("false");
}

/**
* Creates an instance of platform's SocketImpl
*/
@SuppressWarnings("unchecked")
static S createPlatformSocketImpl(boolean server) {
if (USE_PLAINSOCKETIMPL) {
return (S) new PlainSocketImpl(server);
} else {
return (S) new NioSocketImpl(server);
}
}

//......
}
/<string>/<code>

SocketImpl的USE_PLAINSOCKETIMPL取决于usePlainSocketImpl方法,而它会从NetProperties读取dk.net.usePlainSocketImpl配置,如果不为null且不为false,则usePlainSocketImpl方法返回true;createPlatformSocketImpl会根据USE_PLAINSOCKETIMPL来创建PlainSocketImpl或者NioSocketImpl

354: Switch Expressions (Preview)

本特性主要是使用yield替换了break来避免歧义,因为break可以用来进行跳转执行类似goto的操作

<code>    @Test
public void testSwitchYield(){
String dayOfWeek = switch(1){
case 1 -> {
String day = "Monday";
yield day;
}
case 2 -> {
String day = "Tuesday";
yield day;
}
default -> "Unknown";
};
System.out.println(dayOfWeek);
}/<code>

355: Text Blocks (Preview)

本特性主要引入了Text Blocks,使用"""来包围一段text block,可以内置占位符最后使用String.format来填充

<code>    @Test
public void testTextBlock(){
// Without Text Blocks
String html = "\\n" +
" \\n" +
"

Hello, Escapes

\\n" +
" \\n" +
"\\n";
System.out.println(html);

// With Text Blocks
String html2 = """


Hello, %s



""";

System.out.println(String.format(html2, "World"));

String htmlWithNewLine = """


Hello World




""";
System.out.print(htmlWithNewLine);
System.out.println("a new line");
}/<code>

需要注意text blocks不能在一行,另外如果结尾的"""在新的一行则会输出新的一行

细项解读

上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 13 Release Notes,这里举几个例子。

添加项

  • 添加FileSystems.newFileSystem(Path, Map<string>) Method/<string>
  • 新的java.nio.ByteBuffer Bulk get/put Methods Transfer Bytes Without Regard to Buffer Position
  • 支持Unicode 12.1
  • 添加-XX:SoftMaxHeapSize Flag,目前仅仅对ZGC起作用
  • ZGC的最大heap大小增大到16TB

移除项

  • 移除awt.toolkit System Property
  • 移除Runtime Trace Methods
  • 移除-XX:+AggressiveOpts
  • 移除Two Comodo Root CA Certificates、Two DocuSign Root CA Certificates
  • 移除内部的com.sun.net.ssl包

废弃项

  • 废弃-Xverify:none及-noverify
  • 废弃rmic Tool并准备移除
  • 废弃javax.security.cert并准备移除

已知问题

  • 不再支持Windows 2019 Core Server
  • 使用ZIP File System (zipfs) Provider来更新包含Uncompressed Entries的ZIP或JAR可能造成文件损坏

其他事项

  • GraphicsEnvironment.getCenterPoint()及getMaximumWindowBounds()已跨平台统一
  • 增强了JAR Manifest的Class-Path属性处理

jdk.net.URLClassPath.showIgnoredClassPathEntries属性设置为true可以用来帮助查看非法的Class-Path entries

  • 针对Negatively Sized Argument,StringBuffer(CharSequence)及StringBuilder(CharSequence)会抛出NegativeArraySizeException
  • linux的默认进程启动机制已经使用posix_spawn
  • Lookup.unreflectSetter(Field)针对static final fields会抛出IllegalAccessException
  • 使用了java.net.Socket.setSocketImplFactory及java.net.ServerSocket.setSocketFactory方法的要注意,要求客户端及服务端要一致,不能一端使用自定义的factory一端使用默认的factory
  • SocketImpl的supportedOptions, getOption及setOption方法的默认实现发生了变化,默认的supportedOptions返回空,而默认的getOption,及setOption方法抛出UnsupportedOperationException
  • JNI NewDirectByteBuffer创建的Direct Buffer为java.nio.ByteOrder.BIG_ENDIAN
  • Base64.Encoder及Base64.Decoder可能抛出OutOfMemoryError
  • 改进了Serial GC Young pause time report
  • 改进了MaxRAM及UseCompressedOops参数的行为

小结

  • Java13主要新增了如下特性350: Dynamic CDS Archives351: ZGC: Uncommit Unused Memory353: Reimplement the Legacy Socket API354: Switch Expressions (Preview)355: Text Blocks (Preview)
  • 语法层面,改进了Switch Expressions,新增了Text Blocks,二者皆处于Preview状态;API层面主要使用NioSocketImpl来替换JDK1.0的PlainSocketImpl
  • GC层面则改进了ZGC,以支持Uncommit Unused Memory

版本号

<code>java -version
openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)/<code>

从version信息可以看出是build 14+36

特性列表

305:Pattern Matching for instanceof (Preview)

JDK14引入了preview版本的针对instanceof的模式匹配,其用法示例如下

<code>    public boolean isBadRequestError(Exception ex) {
return (ex instanceof HttpClientErrorException rce) &&
HttpStatus.BAD_REQUEST == rce.getStatusCode();
}/<code>

无需在自己进行类型强转

343:Packaging Tool (Incubator)

JDK14引入了jdk.incubator.jpackage.jmod,它基于JavaFX javapackager tool构建,目的在于创建一个简单的打包工具,可以用于构建exe、pkg、dmg、deb、rpm格式的安装文件;非模块化的app的构建示例如下

<code>jpackage --name myapp --input lib --main-jar main.jar/<code>

345:NUMA-Aware Memory Allocation for G1

实现了NUMA-aware的内存分配,以提升G1在大型机器上的性能


JDK 14 新特性-你还跟得上吗


349:JFR Event Streaming

JDK11引入了JFR,使用的时候先dump到磁盘上然后再分析;而在JDK14则支持stream方式来进行持续性的监控,示例如下

<code>public class AgentMain implements Runnable {

public static void premain(String agentArgs, Instrumentation inst) {
try {
Logger.getLogger("AgentMain").log(
Level.INFO, "Attaching JFR Monitor");
new Thread(new AgentMain()).start();
} catch (Throwable t) {
Logger.getLogger("AgentMain").log(
Level.SEVERE,"Unable to attach JFR Monitor", t);
}
}

@Override
public void run() {
var sender = new JfrStreamEventSender();
try (var rs = new RecordingStream()) {
rs.enable("jdk.CPULoad")
.withPeriod(Duration.ofSeconds(1));
rs.enable("jdk.JavaMonitorEnter")
.withThreshold(Duration.ofMillis(10));
rs.onEvent("jdk.CPULoad", sender);
rs.onEvent("jdk.JavaMonitorEnter", sender);
rs.start();
}
}
}/<code>

352:Non-Volatile Mapped Byte Buffers

该特性新增了java.base/jdk/internal/misc/ExtendedMapMode.java以支持MappedByteBuffer访问non-volatile memory (NVM)

358:Helpful NullPointerExceptions

该特性可以更好地提示哪个地方出现的空指针,需要通过-XX:+ShowCodeDetailsInExceptionMessages开启,示例如下

<code>public class NullPointerExample {

public record City(String name){

}

public record Location(City city) {

}

public record User(String name, Location location) {

}

public static void main(String[] args){
User user = new User("hello", new Location(null));
System.out.println(user.location().city().name());
}
}/<code>

输出如下

<code>Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.example.NullPointerExample$City.name()" because the return value of "com.example.NullPointerExample$Location.city()" is null
at com.example.NullPointerExample.main(NullPointerExample.java:25)/<code>

359:Records (Preview)

JDK14引入了preview版本的record类型,示例如下

<code>public record Point(int x, int y) {

public Point {
System.out.println(String.format("(%d,%d)", x, y));
}

public Point(int value) {
this(value, value);
}

public static Point of(int value) {
return new Point(value, value);
}
}/<code>

javap反编译如下

<code>javac --enable-preview -source 14 Point.java 

javap -verbose Point.class
Compiled from "Point.java"
public final class com.example.domain.Point extends java.lang.Record {
public com.example.domain.Point(int, int);
public static com.example.domain.Point of(int);
public java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int x();
public int y();
}/<code>

可以看见Point继承了java.lang.Record,而且通过invokedynamic提供了final的hashCode及equals

361:Switch Expressions (Standard)

JDK12引入的switch在JDK14变为正式版本,正式版主要是用->来替代以前的:+break;另外就是提供了yield来在block中返回值,示例如下

<code>    public void testSwitchWithArrowBlockAndYield() {
int n = 3;
String quantityString = switch (n) {
case 1 -> "one";
case 2 -> "two";
default -> {
System.out.println("default");
yield "many";
}
};
System.out.println(quantityString);
}/<code>

362:Deprecate the Solaris and SPARC Ports

废弃了 Solaris/SPARC, Solaris/x64, and Linux/SPARC ports,以在未来的版本中移除

363:Remove the Concurrent Mark Sweep (CMS) Garbage Collector

移除了CMS垃圾收集器,如果在JDK14中使用-XX:+UseConcMarkSweepGC的话,会出现warning,但是不会exit而是以默认的垃圾收集器运行,如下

<code>OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0/<code>

364:ZGC on macOS

之前的ZGC只能在linux上使用,现在mac上也能使用ZGC了,示例如下

<code>-XX:+UnlockExperimentalVMOptions -XX:+UseZGC/<code>

365:ZGC on Windows

之前的ZGC只能在linux上使用,现在windows(不能低于1803版本)上也能使用ZGC了,示例如下

<code>-XX:+UnlockExperimentalVMOptions -XX:+UseZGC/<code>

366:Deprecate the ParallelScavenge + SerialOld GC Combination

废弃了parallel young generation GC与SerialOld GC的组合( -XX:+UseParallelGC与-XX:-UseParallelOldGC配合开启),现在使用-XX:+UseParallelGC -XX:-UseParallelOldGC或者-XX:-UseParallelOldGC都会出现告警如下

<code>OpenJDK 64-Bit Server VM warning: Option UseParallelOldGC was deprecated in version 14.0 and will likely be removed in a future release./<code>

单独使用-XX:+UseParallelGC则开启parallel young and old generation GC algorithms

367:Remove the Pack200 Tools and API

移除了Pack200 API

368:Text Blocks (Second Preview)

JDK13引入的text blocks进行第二轮preview,JDK14的版本主要增加了两个escape sequences,分别是 \\<line-terminator>与\\s escape sequence,示例如下/<line-terminator>

<code>    @Test
public void testTextBlockWithTwoNewEscapeSequences() {
String inOneLine = """
Lorem ipsum dolor sit amet, consectetur adipiscing \\
elit, sed do eiusmod tempor incididunt ut labore \\
et dolore magna aliqua.\\
""";
System.out.println(inOneLine);

String singleSpace = """
red \\s
green\\s
blue \\s
""";
System.out.println(singleSpace);
}/<code>

370:Foreign-Memory Access API (Incubator)

提供了incubator版本的API用于操纵堆外内存,使用示例如下

<code>    @Test
public void testForeignMemoryAccessAPI() {
SequenceLayout intArrayLayout
= MemoryLayout.ofSequence(25,
MemoryLayout.ofValueBits(32,
ByteOrder.nativeOrder()));

VarHandle intElemHandle
= intArrayLayout.varHandle(int.class,
MemoryLayout.PathElement.sequenceElement());

try (MemorySegment segment = MemorySegment.allocateNative(intArrayLayout)) {
MemoryAddress base = segment.baseAddress();
for (int i = 0; i < intArrayLayout.elementCount().getAsLong(); i++) {
intElemHandle.set(base, (long) i, i);
}
}
}/<code>

细项解读

上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 14 Release Notes,这里举几个例子。

添加项

  • New Method to SAX ContentHandler for Handling XML Declaration (JDK-8230814)

给SAX ContentHandler新增了方法,如下

<code>    default void declaration(String version, String encoding, String standalone)
throws SAXException
{
//no op
}/<code>

移除项

  • Removal of sun.nio.cs.map System Property (JDK-8229960)

移除了sun.nio.cs.map属性

  • Removed Deprecated java.security.acl APIs (JDK-8191138)

移除了java.security.acl

  • Removal of the Default keytool -keyalg Value (JDK-8214024)

移除了默认的keytool -keyalg

废弃项

  • Thread Suspend/Resume Are Deprecated for Removal (JDK-8231602)

废弃了Thread的如下方法

<code>Thread.suspend()
Thread.resume()
ThreadGroup.suspend()
ThreadGroup.resume()
ThreadGroup.allowThreadSuspension(boolean)/<code>

已知问题

  • Text Visibility Issues in macOS Dark Mode (JDK-8228555)

已知在macOS上的Dark Mode有Text Visibility Issues

其他事项

  • Thread.countStackFrames Changed to Unconditionally Throw UnsupportedOperationException (JDK-8205132)

Thread.countStackFrames开启转为无条件地抛出UnsupportedOperationException

小结

Java14主要有如下几个特性

  • 305:Pattern Matching for instanceof (Preview)
  • 349:JFR Event Streaming
  • 352:Non-Volatile Mapped Byte Buffers
  • 358:Helpful NullPointerExceptions
  • 359:Records (Preview)
  • 361:Switch Expressions (Standard)
  • 363:Remove the Concurrent Mark Sweep (CMS) Garbage Collector
  • 364:ZGC on macOS
  • 366:Deprecate the ParallelScavenge + SerialOld GC Combination
  • 368:Text Blocks (Second Preview)
  • 370:Foreign-Memory Access API (Incubator)


分享到:


相關文章: