Java 发布版本
1995年5月23日,Java语言诞生 1996年1月,第一个JDK-JDK1.0诞生 1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入JAVA技术 1996年9月,约8.3万个网页应用了JAVA技术来制作 1997年2月18日,JDK1.1发布 1997年4月2日,JavaOne会议召开,参与者逾一万人,创当时全球同类会议规模之纪录 1997年9月,JavaDeveloperConnection社区成员超过十万 1998年2月,JDK1.1被下载超过2,000,000次 1998年12月8日,JAVA2企业平台J2EE发布 1999年6月,SUN公司发布Java的三个版本:标准版(J2SE)、企业版(J2EE)和微型版(J2ME) 2000年5月8日,JDK1.3发布 2000年5月29日,JDK1.4发布 2001年6月5日,NOKIA宣布,到2003年将出售1亿部支持Java的手机 2001年9月24日,J2EE1.3发布 2002年2月26日,J2SE1.4发布,自此Java的计算能力有了大幅提升 2004年9月30日18:00PM,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性,J2SE1.5更名为Java SE 5.0 2005年6月,JavaOne大会召开,SUN公司公开Java SE 6。此时,Java的各种版本已经更名,以取消其中的数字“2”:J2EE更名为Java EE,J2SE更名为Java SE,J2ME更名为Java ME 2006年12月,SUN公司发布JRE6.0 2009年12月,SUN公司发布Java EE 6 2010年11月,由于Oracle公司对于Java社区的不友善,因此Apache扬言将退出JCP[14] 2011年7月28日,Oracle公司发布Java SE 7 2014年3月18日,Oracle公司发表Java SE 8 2017年9月21日,Oracle公司发表Java SE 9 2018年3月21日,Oracle公司发表Java SE 10 2018年9月25日,Java SE 11发布
JDK9
Java 9 新特性概述
Java 9 正式发布于 2017 年 9 月 21 日。作为 Java8 之后 3 年半才发布的新版本,Java 9 带来了很多重大的变化。其中最重要的改动是 Java 平台模块系统的引入。除此之外,还有一些新的特性。本文对 Java9 中包含的新特性做了概括性的介绍,可以帮助你快速了解 Java 9。
Java 平台 模块系统
Java 平台模块系统,也就是 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。这对于目前流行的不可变基础设施的实践来说,镜像的大小的减少可以节省很多存储空间和带宽资源 。
模块化开发的实践在软件开发领域并不是一个新的概念。Java 开发社区已经使用这样的模块化实践有相当长的一段时间。主流的构建工具,包括 Apache Maven 和 Gradle 都支持把一个大的项目划分成若干个子项目。子项目之间通过不同的依赖关系组织在一起。每个子项目在构建之后都会产生对应的 JAR 文件。 在 Java9 中 ,已有的这些项目可以很容易的升级转换为 Java 9 模块 ,并保持原有的组织结构不变。
Java 9 模块的重要特征是在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。 工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。这个文件由根目录中的源代码文件 module-info.java 编译而来。该模块声明文件可以描述模块的不同特征。模块声明文件中可以包含的内容如下:
- 模块导出的包:使用 exports 可以声明模块对其他模块所导出的包。包中的 public 和 protected 类型,以及这些类型的 public 和 protected 成员可以被其他模块所访问。没有声明为导出的包相当于模块中的私有成员,不能被其他模块使用。
- 模块的依赖关系:使用 requires 可以声明模块对其他模块的依赖关系。使用 requires transitive 可 以把一个模块依赖声明为传递的。传递的模块依赖可以被依赖当前模块的其他模块所读取。 如果一个模块所导出的类型的型构中包含了来自它所依赖的模块的类型,那么对该模块的依赖应该声明为传递的。
- 服务的提供和使用:如果一个模块中包含了可以被 ServiceLocator 发现的服务接口的实现 ,需要使用 provides with 语句来声明具体的实现类 ;如果一个模块需要使用服务接口,可以使用 uses 语句来声明。
代码清单 1 中给出了一个模块声明文件的示例。在该声明文件中,模块 c om.mycompany.sample 导出了 Java 包 com.mycompany.sample。该模块依赖于模块 c om.mycompany.sample 。该模块也提供了服务接口 com.mycompany.common.DemoService 的实现类 c om.mycompany.sample.DemoServiceImpl 。
清单 1. 模块声明示例
module com.mycompany.sample {
exports com.mycompany.sample;
requires com.mycompany.common;
provides com.mycompany.common.DemoService with
com.mycompany.sample.DemoServiceImpl;
}
模块系统中增加了模块路径的概念。模块系统在解析模块时,会从模块路径中进行查找。为了保持与之前 Java 版本的兼容性,CLASSPATH 依然被保留。所有的类型在运行时都属于某个特定的模块。对于从 CLASSPATH 中加载的类型,它们属于加载它们的类加载器对应的未命名模块。可以通过 Class 的 getModule()方法来获取到表示其所在模块的 Module 对象。
在 JVM 启动时,会从应用的根模块开始,根据依赖关系递归的进行解析,直到得到一个表示依赖关系的图。如果解析过程中出现找不到模块的情况,或是在模块路径的同一个地方找到了名称相同的模块,模块解析过程会终止,JVM 也会退出。Java 也提供了相应的 API 与模块系统进行交互。
Jshell
jshell 是 Java 9 新增的一个实用工具。jshell 为 Java 增加了类似 NodeJS 和 Python 中的读取-求值-打印循环( Read-Evaluation-Print Loop ) 。 在 jshell 中 可以直接 输入表达式并查看其执行结果。当需要测试一个方法的运行效果,或是快速的对表达式进行求值时,jshell 都非常实用。只需要通过 jshell 命令启动 jshell,然后直接输入表达式即可。每个表达式的结果会被自动保存下来 ,以数字编号作为引用,类似 $1 和$2 这样的名称 。可以在后续的表达式中引用之前语句的运行结果。 在 jshell 中 ,除了表达式之外,还可以创建 Java 类和方法。jshell 也有基本的代码完成功能。
在 代码清单 2 中,我们直接创建了一个方法 add。
清单 2. 在 jshell 中添加方法
jshell> int add(int x, int y) {
...> return x + y;
...> }
| created method add(int,int)
接着就可以在 jshell 中直接使用这个方法,如 代码清单 3 所示。
清单 3. 在 jshell 中使用创建的方法
jshell> add(1, 2)
$19 ==> 3
集合、Stream 和 Optional
在集合上,Java 9 增加 了 List.of()、Set.of()、Map.of() 和 M ap.ofEntries()等工厂方法来创建不可变集合 ,如 代码清单 4 所示。
清单 4 . 创建不可变集合
List.of();
List.of("Hello", "World");
List.of(1, 2, 3);
Set.of();
Set.of("Hello", "World");
Set.of(1, 2, 3);
Map.of();
Map.of("Hello", 1, "World", 2);
Stream 中增加了新的方法 ofNullable、dropWhile、takeWhile 和 iterate。在 代码清单 5 中,流中包含了从 1 到 5 的 元素。断言检查元素是否为奇数。第一个元素 1 被删除,结果流中包含 4 个元素。
清单 5 . Stream 中的 dropWhile 方法示例
@Test
public void testDropWhile() throws Exception {
final long count = Stream.of(1, 2, 3, 4, 5)
.dropWhile(i -> i % 2 != 0)
.count();
assertEquals(4, count);
}
Collectors 中增加了新的方法 filtering 和 flatMapping。在 代码清单 6 中,对于输入的 String 流 ,先通过 flatMapping 把 String 映射成 Integer 流 ,再把所有的 Integer 收集到一个集合中。
清单 6 . Collectors 的 flatMapping 方法示例
@Test
public void testFlatMapping() throws Exception {
final Set<Integer> result = Stream.of("a", "ab", "abc")
.collect(Collectors.flatMapping(v -> v.chars().boxed(),
Collectors.toSet()));
assertEquals(3, result.size());
}
Optiona l 类中新增了 ifPresentOrElse、or 和 stream 等方法。在 代码清单 7 中,Optiona l 流中包含 3 个 元素,其中只有 2 个有值。在使用 flatMap 之后,结果流中包含了 2 个值。
清单 7 . Optional 的 stream 方法示例
@Test
public void testStream() throws Exception {
final long count = Stream.of(
Optional.of(1),
Optional.empty(),
Optional.of(2)
).flatMap(Optional::stream)
.count();
assertEquals(2, count);
}
进程 API
Java 9 增加了 ProcessHandle 接口,可以对原生进程进行管理,尤其适合于管理长时间运行的进程。在使用 P rocessBuilder 来启动一个进程之后,可以通过 Process.toHandle()方法来得到一个 ProcessHandl e 对象的实例。通过 ProcessHandle 可以获取到由 ProcessHandle.Info 表 示的进程的基本信息,如命令行参数、可执行文件路径和启动时间等。ProcessHandle 的 onExit()方法返回一个 C ompletableFuture对象,可以在进程结束时执行自定义的动作。 代码清单 8 中给出了进程 API 的使用示例。
清单 8 . 进程API 示例
final ProcessBuilder processBuilder = new ProcessBuilder("top")
.inheritIO();
final ProcessHandle processHandle = processBuilder.start().toHandle();
processHandle.onExit().whenCompleteAsync((handle, throwable) -> {
if (throwable == null) {
System.out.println(handle.pid());
} else {
throwable.printStackTrace();
}
});
平台日志 API 和 服务
Java 9 允许为 JDK 和应用配置同样的日志实现。新增的 System.LoggerFinder 用来管理 JDK 使 用的日志记录器实现。JVM 在运行时只有一个系统范围的 LoggerFinder 实例。LoggerFinder 通 过服务查找机制来加载日志记录器实现。默认情况下,JDK 使用 java.logging 模块中的 java.util.logging 实现。通过 LoggerFinder 的 getLogger()方法就可以获取到表示日志记录器的 System.Logger 实现。应用同样可以使用 System.Logger 来记录日志。这样就保证了 JDK 和应用使用同样的日志实现。我们也可以通过添加自己的 System.LoggerFinder 实现来让 JDK 和应用使用 SLF4J 等其他日志记录框架。 代码清单 9 中给出了平台日志 API 的使用示例。
清单 9.使用平台日志 API
public class Main {
private static final System.Logger LOGGER = System.getLogger("Main");
public static void main(final String[] args) {
LOGGER.log(Level.INFO, "Run!");
}
}
反应式流 ( Reactive Streams )
反应式编程的思想最近得到了广泛的流行。 在 Java 平台上有流行的反应式 库 RxJava 和 R eactor。反应式流规范的出发点是提供一个带非阻塞负压( non-blocking backpressure ) 的异步流处理规范。反应式流规范的核心接口已经添加到了 Java9 中的 java.util.concurrent.Flow 类中。
Flow 中包含了 Flow.Publisher、Flow.Subscriber、Flow.Subscription 和 F low.Processor 等 4 个核心接口。Java 9 还提供了 SubmissionPublisher 作为 Flow.Publisher 的一个实现。RxJava 2 和 Reactor 都可以很方便的 与 Flow 类的核心接口进行互操作。
变量句柄
变量句柄是一个变量或一组变量的引用,包括静态域,非静态域,数组元素和堆外数据结构中的组成部分等。变量句柄的含义类似于已有的方法句柄。变量句柄由 J ava 类 java.lang.invoke.VarHandle 来表示。可以使用类 j ava.lang.invoke.MethodHandles.Looku p 中的静态工厂方法来创建 VarHandle 对 象。通过变量句柄,可以在变量上进行各种操作。这些操作称为访问模式。不同的访问模式尤其在内存排序上的不同语义。目前一共有 31 种 访问模式,而每种访问模式都 在 VarHandle 中 有对应的方法。这些方法可以对变量进行读取、写入、原子更新、数值原子更新和比特位原子操作等。VarHandle 还 可以用来访问数组中的单个元素,以及把 byte[]数组 和 ByteBuffer 当成是不同原始类型的数组来访问。
在 代码清单 10 中,我们创建了访问 HandleTarget 类中的域 count 的变量句柄,并在其上进行读取操作。
清单 10. 变量句柄使用示例
public class HandleTarget {
public int count = 1;
}
public class VarHandleTest {
private HandleTarget handleTarget = new HandleTarget();
private VarHandle varHandle;
@Before
public void setUp() throws Exception {
this.handleTarget = new HandleTarget();
this.varHandle = MethodHandles
.lookup()
.findVarHandle(HandleTarget.class, "count", int.class);
}
@Test
public void testGet() throws Exception {
assertEquals(1, this.varHandle.get(this.handleTarget));
assertEquals(1, this.varHandle.getVolatile(this.handleTarget));
assertEquals(1, this.varHandle.getOpaque(this.handleTarget));
assertEquals(1, this.varHandle.getAcquire(this.handleTarget));
}
}
改进方法句柄(Method Handle)
类 java.lang.invoke.MethodHandles 增加了更多的静态方法来创建不同类型的方法句柄。
- arrayConstructor:创建指定类型的数组。
- arrayLength:获取指定类型的数组的大小。
- varHandleInvoker 和 varHandleExactInvoker:调用 VarHandle 中的访问模式方法。
- zero:返回一个类型的默认值。
- empty:返 回 MethodType 的返回值类型的默认值。
- loop、countedLoop、iteratedLoop、whileLoop 和 doWhileLoop:创建不同类型的循环,包括 for 循环、while 循环 和 do-while 循环。
- tryFinally:把对方法句柄的调用封装在 try-finally 语句中。
在 代码清单 11 中,我们使用 iteratedLoop 来创建一个遍历 S tring 类型迭代器的方法句柄,并计算所有字符串的长度的总和。
清单 11. 循环方法句柄使用示例
public class IteratedLoopTest {
static int body(final int sum, final String value) {
return sum + value.length();
}
@Test
public void testIteratedLoop() throws Throwable {
final MethodHandle iterator = MethodHandles.constant(
Iterator.class,
List.of("a", "bc", "def").iterator());
final MethodHandle init = MethodHandles.zero(int.class);
final MethodHandle body = MethodHandles
.lookup()
.findStatic(
IteratedLoopTest.class,
"body",
MethodType.methodType(
int.class,
int.class,
String.class));
final MethodHandle iteratedLoop = MethodHandles
.iteratedLoop(iterator, init, body);
assertEquals(6, iteratedLoop.invoke());
}
}
并发
在并发方面,类 CompletableFuture 中增加了几个新的方法。completeAsync 使用一个异步任务来获取结果并完成该 CompletableFuture。orTimeout 在 CompletableFuture 没有在给定的超时时间之前完成,使用 TimeoutException 异常来完成 CompletableFuture。completeOnTimeout 与 o rTimeout 类似,只不过它在超时时使用给定的值来完成 CompletableFuture。新的 Thread.onSpinWai t 方法在当前线程需要使用忙循环来等待时,可以提高等待的效率。
Nashorn
Nashorn 是 Java 8 中引入的新的 JavaScript 引擎。Java 9 中的 Nashorn 已经实现了一些 ECMAScript 6 规范中的新特性,包括模板字符串、二进制和八进制字面量、迭代器 和 for..of 循环和箭头函数等。Nashorn 还提供了 API 把 ECMAScript 源代码解析成抽象语法树( Abstract Syntax Tree,AST ) ,可以用来对 ECMAScript 源代码进行分析。
I/O 流新特性
类 java.io.InputStream 中增加了新的方法来读取和复制 InputStream 中包含的数据。
- readAllBytes:读取 InputStream 中的所有剩余字节。
- readNBytes: 从 InputStream 中读取指定数量的字节到数组中。
- transferTo:读取 InputStream 中的全部字节并写入到指定的 OutputStream 中 。
代码清单 12 中给出了这些新方法的使用示例。
清单 12. InputStream 中的新方法使用示例
public class TestInputStream {
private InputStream inputStream;
private static final String CONTENT = "Hello World";
@Before
public void setUp() throws Exception {
this.inputStream =
TestInputStream.class.getResourceAsStream("/input.txt");
}
@Test
public void testReadAllBytes() throws Exception {
final String content = new String(this.inputStream.readAllBytes());
assertEquals(CONTENT, content);
}
@Test
public void testReadNBytes() throws Exception {
final byte[] data = new byte[5];
this.inputStream.readNBytes(data, 0, 5);
assertEquals("Hello", new String(data));
}
@Test
public void testTransferTo() throws Exception {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
this.inputStream.transferTo(outputStream);
assertEquals(CONTENT, outputStream.toString());
}
}
ObjectInputFilter 可以对 ObjectInputStream 中 包含的内容进行检查,来确保其中包含的数据是合法的。可以使用 ObjectInputStream 的方法 setObjectInputFilter 来设置。ObjectInputFilter 在 进行检查时,可以检查如对象图的最大深度、对象引用的最大数量、输入流中的最大字节数和数组的最大长度等限制,也可以对包含的类的名称进行限制。
改进应用安全性能
Java 9 新增了 4 个 SHA- 3 哈希算法,SHA3-224、SHA3-256、SHA3-384 和 S HA3-512。另外也增加了通过 java.security.SecureRandom 生成使用 DRBG 算法的强随机数。代码清单 13 中给出了 SHA-3 哈希算法的使用示例。
清单 13. SHA-3 哈希算法使用示例
import org.apache.commons.codec.binary.Hex;
public class SHA3 {
public static void main(final String[] args) throws NoSuchAlgorithmException {
final MessageDigest instance = MessageDigest.getInstance("SHA3-224");
final byte[] digest = instance.digest("".getBytes());
System.out.println(Hex.encodeHexString(digest));
}
}
用户界面
类 java.awt.Desktop 增加了新的与桌面进行互动的能力。可以使用 addAppEventListener 方法来添加不同应用事件的监听器,包括应用变为前台应用、应用隐藏或显示、屏幕和系统进入休眠与唤醒、以及 用户会话的开始和终止等。还可以在显示关于窗口和配置窗口时,添加自定义的逻辑。在用户要求退出应用时,可以通过自定义处理器来接受或拒绝退出请求。在 A WT 图像支持方面,可以在应用中使用多分辨率图像。
统一 JVM 日志
Java 9 中 ,JVM 有了统一的日志记录系统,可以使用新的命令行选项-Xlog 来控制 JVM 上 所有组件的日志记录。该日志记录系统可以设置输出的日志消息的标签、级别、修饰符和输出目标等。Java 9 移除了在 Java 8 中 被废弃的垃圾回收器配置组合,同时 把 G1 设为默认的垃圾回收器实现。另外,CMS 垃圾回收器已经被声明为废弃。Java 9 也增加了很多可以通过 jcmd 调用的诊断命令。
其他改动方面
在 Java 语言本身,Java 9 允许在接口中使用私有方法。 在 try-with-resources 语句中可以使用 e ffectively-final 变量。 类 java.lang.StackWalker 可 以对线程的堆栈进行遍历,并且支持过滤和延迟访问。Java 9 把对 Unicode 的支持升级到了 8.0。ResourceBundle 加载属性文件的默认编码从 ISO-8859-1 改成了 UTF-8,不再需要使用 native2ascii 命 令来对属性文件进行额外处理。注解@Deprecated 也得到了增强,增加了 since 和 forRemoval 两 个属性,可以分别指定一个程序元素被废弃的版本,以及是否会在今后的版本中被删除。
在代码清单 14 中,buildMessage 是接口 SayHi 中的私有方法,在默认方法 sayHi 中被使用。
清单 14. 接口中私有方法的示例
public interface SayHi {
private String buildMessage() {
return "Hello";
}
void sayHi(final String message);
default void sayHi() {
sayHi(buildMessage());
}
}
结束语
作为 Java 平台最新的一个重大更新,Java 9 中的很多新特性,尤其模块系统,对于 Java 应用的开发会产生深远的影响。本文对 Java 9 中的新特性做了概括的介绍,可以作为了解 Java 9 的基础。这些新特性的相信内容,可以通过官方文档来进一步的了解。
摘自:https://developer.ibm.com/zh/articles/the-new-features-of-java-9/
JDK10
JDK10 新特性
虽然感觉 JDK9 发布才仅仅几周的时间,然而,随着新的 OpenJDK 的发布节奏,JDK10 已经到达发布候选里程碑阶段。
我看过各种关于 JDK10 新特性的博客,但是它们都倾向于关注通过 JEPS 定义的大方面。这篇博文,我将看看是否可以罗列出 JDK10 中已经发生变化的方方面面(包括新增的和剔除的)。
有时候,我会做一些关于 Java SE 的报告会。之前我在“ JDK9 的 55 个新特性”的报告会上曾开玩笑说:下次我将做的恐怕是“ JDK10 的 5 个新特性”。然而事实证明,即使仅有六个多月的开发时间,JDK10 依然超乎想象。
即便我不再为 Oracle 工作,我也在此先做一个“安全港声明”,以便消除误会。这个列表是由下面这些公开可用的信息整理编辑的:JDK Enhancement Proposals (JEPs)、the OpenJDK bug database 和 Java SE 10 public review specification (JSR 383) 。当然,尽管我已尽可能的研究以保证信息准确,但在 JDK 10 最终发布之前仍可能会发生变化。
大事记
JDK10 包含 12 个JEP (改善提议):
-
【286】局部变量类型推断 :对于开发者来说,这是 JDK10 唯一的真正特性。它向 Java 中引入在其他语言中很常见的 var ,比如 JavaScript 。只要编译器可以推断此种类型,你不再需要专门声明一个局部变量的类型。一个简单的例子是:
var x = new ArrayList<String>();
这就消除了我们之前必须执行的 ArrayList<String> 类型定义的重复。我鼓励你们去读 JEP ,因为上面有一些关于这个句法是否能用的规则。
有趣的是,需要注意 var 不能成为一个关键字,而是一个保留字。这意味着你仍然可以使用 var 作为一个变量,方法或包名,但是现在(尽管我确定你绝不会)你不能再有一个类被调用。
-
[310]应用类数据共享(CDS) :CDS 在 JDK5 时被引进以改善 JVM 启动的表现,同时减少当多个虚拟机在同一个物理或虚拟的机器上运行时的资源占用。
JDK10 将扩展 CDS 到允许内部系统的类加载器、内部平台的类加载器和自定义类加载器来加载获得的类。之前,CDS 的使用仅仅限制在了 bootstrap 的类加载器。
-
[314]额外的 Unicode 语言标签扩展:这将改善 java.util.Locale 类和相关的 API 以实现额外 BCP 47 语言标签的 Unicode 扩展。尤其是,货币类型,一周的第一天,区域覆盖和时区等标签现在将被支持。
-
[322]基于时间的版本控制:正如我在之前的博客中所讨论的,我们的 JDK 版本字符串格式几乎与 JDK 版本一样多。有幸的是,这是最后需要使用到的,我们可以坚持用它。这种格式使用起来很像 JDK9 中介绍的提供一个更加语义的形式。有一件困扰我的事是包含了一个 INTERIM 元素,正如 JEP 提议中所说,“永远是0”。好吧,如果永远是0,那它有什么意义呢?他们说这是为未来使用做保留,但我仍不是很赞同。我认为,这有些冗余繁杂。
这也消除了在 JDK9 中有过的相当奇怪的情形。第一次更新是 JDK 9.0.1 , 非常符合逻辑。第二次更新是 JDK 9.0.4 ,不合逻辑。原因是,在 JDK9 的版本计数模式下,需要留下空白以便应急或不在预期安排的更新使用。但既然没有更新是必须的,为什么不简单称之为 JDK 9.0.2 呢?
-
[319]根证书:在 JDK 中将提供一套默认的 CA 根证书。关键的安全部件,如 TLS ,在 OpenJDK 构建中将默认有效。这是 Oracle 正在努力确保 OpenJDK 二进制和 Oracle JDK 二进制功能上一样的工作的一部分,是一项有用的补充内容。
-
[307] 并行全垃圾回收器 G1 : G1 是设计来作为一种低延时的垃圾回收器(但是如果它跟不上旧的堆碎片产生的提升速率的话,将仍然采用完整压缩集合)。在 JDK9 之前,默认的收集器是并行,吞吐,收集器。为了减少在使用默认的收集器的应用性能配置文件的差异,G1 现在有一个并行完整收集机制。
-
[313]移除 Native-Header 自动生成工具:Java9 开始了一些对 JDK 的家务管理,这项特性是对它的延续。当编译 JNI 代码时,已不再需要单独的工具来生成头文件,因为这可以通过 javac 完成。在未来的某一时刻,JNI 将会被 Panama 项目的结果取代,但是何时发生还不清楚。
-
[304]垃圾回收器接口: 这不是让开发者用来控制垃圾回收的接口;而是一个在 JVM 源代码中的允许另外的垃圾回收器快速方便的集成的接口。
-
[312]线程-局部变量管控:这是在 JVM 内部相当低级别的更改,现在将允许在不运行全局虚拟机安全点的情况下实现线程回调。这将使得停止单个线程变得可能和便宜,而不是只能启用或停止所有线程。
-
[316]在备用存储装置上的堆分配:硬件技术在持续进化,现在可以使用与传统 DRAM 具有相同接口和类似性能特点的非易失性 RAM 。这项 JEP 将使得 JVM 能够使用适用于不同类型的存储机制的堆。
-
[317] 试验性的基于 Java 的 JIT 编译器:最近宣布的 Metropolis 项目,提议用 Java 重写大部分 JVM 。乍一想,觉得很奇怪。如果 JVM 是用 Java 编写的,那么是否需要一个 JVM 来运行 JVM ? 相应的,这导致了一个很好的镜像类比。 现实情况是,使用 Java 编写 JVM 并不意味着必须将其编译为字节码,你可以使用 AOT 编译,然后在运行时编译代码以提高性能。
这项 JEP 将 Graal 编译器研究项目引入到 JDK 中。并给将 Metropolis 项目成为现实,使 JVM 性能与当前 C++ 所写版本匹敌(或有幸超越)提供基础。
-
[296]: 合并 JDK 多个代码仓库到一个单独的储存库中:在 JDK9 中,有 8 个仓库: root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn 。在 JDK10 中这些将被合并为一个,使得跨相互依赖的变更集的存储库运行 atomic commit (原子提交)成为可能。
新 API
有 73 项新增内容添加到了标准类库中。
-
java.awt.Toolkit
int getMenuShortcutKeyMaskEx(): 确定哪个扩展修饰符键是菜单快捷键的适当加速键。 -
java.awt.geom.Path2D:
void trimToSize(): 将此 Path2D 实例的容量计算到它当前的大小。应用可使用此操作将路径的存储空间最小化。这个方法也被添加到 Path2D.Double 和 Path2D.Float 类。 -
java.io.ByteArrayOutputStream:
String toString(Charset): 重载 toString(),通过使用指定的字符集解码字节,将缓冲区的内容转换为字符串。 -
java.io.PrintStream:
lang.io.PrintWriter:
这两个类都有三个新的构造函数,它们需要额外的 Charset 参数。 -
java.io.Reader:
long transferTo(Writer): 从这个 Reader 中读取所有字符,并按照所读的顺序将字符写入给定的 Writer 。 -
java.lang.Runtime.Version:
有四种新方法返回新(JEP 322)版本字符串字段的整数值: feature()、interim()、patch() 和 update() 。
-
java.lang.StackWalker.StackFrame:
String getDescriptor(): 按照 JVM 标准返回此堆栈帧所代表的方法的描述符。
String getMethodType():返回此堆栈帧所代表的方法类型,描述参数类型和返回值类型。 -
java.lang.invoke.MethodType:
Class<?> lastParameterType():返回这个方法类型的最后一个参数类型。如果这个方法类型没有参数,则返回空类型作为岗哨值(Sentinel Value)。 -
java.lang.management.RuntimeMXBean:
long getPid(): R 返回正在运行的 JVM 的进程 ID 。 -
java.lang.management.ThreadMXBean:
ThreadInfo[] dumpAllThreads(boolean, boolean, int): 返回所有活动线程的线程信息,其中有指定的最大元素数量和同步信息的堆栈跟踪。
ThreadInfo[] getThreadInfo(long[], boolean, boolean, int): 返回每个线程的线程信息,这些线程的标识位于输入数组中,其中有指定的最大元素数量和同步信息的堆栈跟踪。 -
java.lang.reflect.MalformedParameterizedTypeException: 添加了一个新的构造函数,它以字符串的形式作为参数来获取详细信息。
-
java.net.URLDecoder:
java.net.URLEncoder:
这两个类都有新的重载的解码和编码方法,将 charset 作为附加参数。
-
java.nio.channels.Channels:
两个新的静态重载方法,允许使用 Charset 的 newReader(ReadByteChannel,Charset)和newWriter(WriteByteChannel,Charset)。 -
java.nio.file.FileStore:
long getBlockSize(): 在这个文件存储中返回每个块的字节数。 -
java.time.chrono: 这个包里有三个类,HijrahEra、MiinguoEra 和 ThaiBuddhistEra ,都有同样的方法。
String getDisplayName(TextStyle, Locale): 这将返回用于识别 era 的文本名称,适合于向用户展示。 -
java.time.format.DateTimeFormatter:
localizedBy(Locale): 返回指定格式器的一个副本,其中包含地区、日历、区域、小数和/或时区的本地化值,这将取代该格式器中的值。 -
java.util: DoubleSummaryStatistics、IntSummaryStatistics 和 LongSummaryStatistics 都有一个新的构造函数,它包含 4 个数值。它使用指定的计数、最小值、最大值和总和构造一个非空实例。
-
java.util.List:
java.util.Map:
java.util.Set: 这些接口中的每一个都增加了一个新的静态方法,copyOf(Collection)。这些函数按照其迭代顺序返回一个不可修改的列表、映射或包含给定集合的元素的集合。 -
java.util.Optional:
java.util.OptionalDouble:
java.util.OptionalInt:
java.util.OptionalLong: 每一个类都有一个新的方法,orElseThrow() ,它本质上和 get() 一样,也就是说,如果 Optional 有值则返回。否则,将抛出 NoSuchElementException 。 -
java.util.Formatter:
java.util.Scanner:
这两个类都有三个新的构造函数,除了其他参数之外,它们都带有一个 charset 参数。
-
java.util.Properties: 这有一个新的构造函数,它接受一个 int 参数。这将创建一个没有默认值的空属性列表,并且指定初始大小以容纳指定的元素数量,而无需动态调整大小。还有一个新的重载的 replace 方法,接受三个 Object 参数并返回一个布尔值。只有在当前映射到指定值时,才会替换指定键的条目。
-
java.SplittableRandom:
void nextBytes(byte[]): 用生成的伪随机字节填充一个用户提供的字节数组。 -
java.util.concurrent.FutureTask: 添加了 toString() 方法,该方法返回一个标识 FutureTask 的字符串,以及它的完成状态。在括号中,状态包含如下字符串中的一个,“Completed Normally” 、“Completed Exceptionally”、 “Cancelled” 或者 “Not completed”。
-
java.util.concurrent.locks.StampedLock:
boolean isLockStamp(long): 返回一个标记戳表示是否持有一个锁。
boolean isOptimisticReadStamp(long): 返回一个标记戳代表是否成功的进行了乐观读(optimistic read)。
boolean isReadLockStamp(long): 返回一个标记戳表示是否持有一个非独占锁(即 read lock )。
boolean isWriteLockStamp(long): 返回一个标记戳表示是否持有一个独占锁(即 write lock )。 -
java.jar.JarEntry:
String getRealName(): 返回这个 JarEntry 的真实名称。如果这个 JarEntry 是一个多版本 jar 文件的入口,它被配置为这样处理,这个方法返回的名字是 JarEntry 所代表的版本条目的入口,而不是 ZipEntry.getName() 返回的基本条目的路径名。如果 JarEntry 不代表一个多版本 jar 文件的版本化条目或者 jar 文件没有被配置为作为一个多版本 jar 文件进行处理,这个方法将返回与 ZipEntry.getName() 返回的相同名称。 -
java.util.jar.JarFile:
Stream<JarEntry> versionedStream(): 返回 jar 文件中指定版本的入口对应 Stream 。与 JarEntry 的 getRealName 方法类似,这与多版本 jar 文件有关。 -
java.util.spi.LocaleNameProvider:
getDisplayUnicodeExtensionKey(String, Locale): 为给定的 Unicode 扩展键返回一个本地化名称。
getDisplayUnicodeExtensionType(String, String, Locale): 为给定的 Unicode 扩展键返回一个本地化名称。 -
java.util.stream.Collectors:
toUnmodifiableList():
toUnmodifiableSet():
toUnmodifiableMap(Function, Function):
toUnmodifiableMap(Function, Function, BinaryOperator): 这四个新方法都返回 Collectors ,将输入元素聚集到适当的不可修改的集合中。
-
java.lang.model.SourceVersion: 现在有了一个字段,它代表了 JDK 10 的版本。
-
java.lang.model.util.TypeKindVisitor6:
javax.lang.model.util.TypeKindVisitor9:
(我必须承认,我从来没听说过这些类)
R visitNoTypeAsModule(NoType, P): 访问一个 MODULE 的 pseudo-type 。我不确定为什么只有这两个类得到这个方法,因为还有 Visitor7 和 Visitor8 变量。 -
javax.remote.management.rmi.RMIConnectorServer:
这个类已经添加了两个字段: CREDENTIALS_FILTER_PATTERN 和 SERIAL_FILTER_PATTERN 。 -
javax.ButtonModel:看,Swing 还在更新!
ButtonGroup getGroup(): 返回按钮所属的组。通常用于单选按钮,它们在组中是互斥的。 -
javax.plaf.basic.BasicMenuUI:
Dimension getMinimumSize(JComponent): 返回指定组件适合观感的最小大小。
JVM 规范改动
这些改动相当小:
-
4.6节:类文件格式(第99页)。在方法访问标志方面有小的改动。
-
4.7节:模块属性(第169页)。如果模块不是 java.base ,则 JDK 10 不再允许设置 ACC_TRANSITIVE 或 ACC_STATIC_PHASE 。
-
4.10节:类文件的校验(第252页)。dup2 指令已改变了 typesafe form 1 的定义,颠倒了 canSafleyPushList 一节中类型的顺序(你需要仔细查看才能发现它)。
-
5.2节:Java 虚拟机启动(第350页)。该描述添加了在创建初始类或接口时可使用用户定义的类加载器( bootstrap 类加载器除外)。
对 Java 语言规范的更改
这里还有一些更改,但主要是为了支持局部变量类型推断。
-
第3.8节:标识符(第23页)。在忽略了可忽略的字符之后,标识符的等价性现在被考虑了。这似乎是合乎逻辑的。
(第24页)一个新的 Token,TypeIdentifier,它支持对局部变量类型推断的新用法,而 var 的使用不是关键字,而是一个具有特殊含义的标识符,作为局部变量声明的类型。 -
第4.10.5节:类型预测(第76页)。这是一个相当复杂的部分,它涉及到捕获变量、嵌套类以及如何使用局部变量类型推断。我建议你阅读规范中的这一部分,而不是试图解释它。
-
第6.1节:声明(第134页)。一个反映使用 TypeIdentifier 来支持局部变量类型的推断的小改动。
-
第6.5节:确定名字的含义(第153页,第158页和第159页)。根据类型标识符的使用而更改类类型。
-
第6.5.4.1:简单的 PackageOrTypeNames(第160页)
-
第6.5.4.2节:合规的 PackageOrTypeNames(第160页)。这两种方式都与使用 TypeIdentifier 有细微的变化。
-
第7.5.3:单静态导入声明(第191页)。这改变了导入具有相同名称的静态类型的规则。除非类型是相同的,否则这将成为一个错误,在这种情况下,重复被忽略。
-
第7.7.1:依赖(第198页)。如果你明确声明一个模块需要 java.base ,那在必要的关键字之后,你就不能再使用修饰符(例如静态)了。
-
第8部分:正式参数(第244页)。接收者参数可能只出现在一个实例方法的 formalparameters 列表,或者是一个内部类的构造函数中,其中内部类没有在静态上下文中声明。
-
第9.7.4节:注释可能出现的地方(第335页)。有一个与局部变量类型推断相关的变更。
-
第14.4部分:局部变量声明语句(第433页)。实现局部变量类型推断所需的大量更改。
-
第14节:增强的 for 语句(第455页)。这个结构已经更新,包括对局部变量类型推断的支持。
-
第14.20.3节:try-with-resources(474页)。这个结构已经更新,包括对局部变量类型推断的支持。
最后,第 19 章有多处语法更新,反映了应更多使用 TypeIdentifier 类型标识符,而不仅仅是 Identifier 标识符,以支持局部变量类型推断。
杂项
-
如果 Kerberos 的配置文件 krb5.conf 包含一个 INCLUDEDIR 选项,那么在 INCLUDEDIR 这个目录下所有以 .conf 结尾的文件都会被默认加载进来。
-
以前版本中已经过期的 Java 的启动选项 -d32 和 –d64 在当前版本已经被移除。如果你在新的版本里仍然使用了这两个选项,JVM 将无法正常启动。
-
JDK10 支持 JDK9 中的新版本 Doclet,JDK6、JDK7、JDK8 中的 Doclet 版本都不再支持。
-
JDK10 重新启用了在 JDK9 中被不当过时的 newFactory() 方法。
-
JDK10 引入了一个新的 Javadoc 标签: {@summary…},解决了以前版本无法生成 API 摘要的问题。
-
JDK10 去掉了 BiasedLockingStartupDelay 的 4 秒启动延时。
-
以下在 com.sun.security.auth 包中的过时的类在新版本中都已经被移除:
-
PolicyFile
-
SolarisNumericGroupPrincipal
-
SolarisNumericUserPrincipal
-
X500Principal
-
SolarisLoginModule
-
SolarisSystem
-
在 java.lang.SecurityManager 类中的以下属性和方法(从 JDK 1.2 就已经过时)终于被移除了:
-
inCheck (属性)
-
getInCheck
-
classDepth
-
classLoaderDepth
-
currentClassLoader
-
currentLoadedClass
-
inClass
-
inClassLoader
-
以下 java.lang.Runtime 类中已经被废弃的国际化方法在新版本被移除:
-
getLocalizedInputStream
-
getLocalizedOutputStream
-
以下废弃的 Hotspot –X 选项在新版本中被移除:-Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads and –Xusealtsigs.
-
policytool 在新版本中被移除。
-
javadoc 工具在新版本中可以通过 –add-stylesheets 命令选项支持多个 stylesheets 。
-
新版本的 JVM 能够根据系统分配给当前 Docker 容器的 CPU 数和内存来配置线程池和 GC 机制,而不再是直接使用系统的 CPU 和内存。并且增加了三个更强大的命令选项:-XX:InitialRAMPercentage、-XX:MaxRAMPercentage 和 -XX:MinRAMPercentage 。
-
新版本增加了一个新的系统属性:jdk.disableLastUsageTracking。这个新增的属性就像它的名字一样,会禁用 JRE 的上一次使用跟踪。
如上所述,尽管距离 JDK 9 发布仅有六个月的时间,但 JDK 10 实际上有相当多的变化。当然,它们中的一些是非常小的变更,但我认为这表明目前每 6 个月发布一次的节奏,将在 Java 平台快速迭代改进方面起到作用。
同时也让我们期待 JDK 11 将带来些什么…
摘自:https://www.oschina.net/translate/109-new-features-in-jdk-10?lang=chs&p=2
评论(41)
引用来自“莫默磨墨先生”的评论
引用来自“laden666666”的评论
引用来自“莫默磨墨先生”的评论
引用来自“zwcloud”的评论
引用来自“莫默磨墨先生”的评论
引用来自“laden666666”的评论
引用来自“莫默磨墨先生”的评论
引用来自“hulk0505”的评论
引用来自“莫默磨墨先生”的评论
引用来自“laden666666”的评论
JDK11
Java 11 新特性介绍
Java 11 已于 2018 年 9 月 25 日正式发布,之前在 Java 10 新特性介绍 中介绍过,为了加快的版本迭代、跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个大版本,每个季度发布一个中间特性版本,并且做出不会跳票的承诺。通过这样的方式,Java 开发团队能够将一些重要特性尽早的合并到 Java Release 版本中,以便快速得到开发者的反馈,避免出现类似 Java 9 发布时的两次延期的情况。
按照官方介绍,新的版本发布周期将会严格按照时间节点,于每年的 3 月和 9 月发布,Java 11 发布的时间节点也正好处于 Java 8 免费更新到期的前夕。与 Java 9 和 Java 10 这两个被称为”功能性的版本”不同,Java 11 仅将提供长期支持服务(LTS, Long-Term-Support),还将作为 Java 平台的默认支持版本,并且会提供技术支持直至 2023 年 9 月,对应的补丁和安全警告等支持将持续至 2026 年。
本文主要针对 Java 11 中的新特性展开介绍,让您快速了解 Java 11 带来的变化。
基于嵌套的访问控制
与 Java 语言中现有的嵌套类型概念一致, 嵌套访问控制是一种控制上下文访问的策略,允许逻辑上属于同一代码实体,但被编译之后分为多个分散的 class 文件的类,无需编译器额外的创建可扩展的桥接访问方法,即可访问彼此的私有成员,并且这种改进是在 Java 字节码级别的。
在 Java 11 之前的版本中,编译之后的 class 文件中通过 InnerClasses 和 Enclosing Method 两种属性来帮助编译器确认源码的嵌套关系,每一个嵌套的类会编译到自己所在的 class 文件中,不同类的文件通过上面介绍的两种属性的来相互连接。这两种属性对于编译器确定相互之间的嵌套关系已经足够了,但是并不适用于访问控制。这里大家可以写一段包含内部类的代码,并将其编译成 class 文件,然后通过 javap
命令行来分析,碍于篇幅,这里就不展开讨论了。
Java 11 中引入了两个新的属性:一个叫做 NestMembers 的属性,用于标识其它已知的静态 nest 成员;另外一个是每个 nest 成员都包含的 NestHost 属性,用于标识出它的 nest 宿主类。
标准 HTTP Client 升级
Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。
新版 Java 中,Http Client 的包名由 jdk.incubator.http 改为 java.net.http,该 API 通过 CompleteableFutures 提供非阻塞请求和响应语义,可以联合使用以触发相应的动作,并且 RX Flo w 的概念也在 Java 11 中得到了实现。现在,在用户层请求发布者和响应发布者与底层套接字之间追踪数据流更容易了。这降低了复杂性,并最大程度上提高了 HTTP/1 和 HTTP/2 之间的重用的可能性。
Java 11 中的新 Http Client API,提供了对 HTTP/2 等业界前沿标准的支持,同时也向下兼容 HTTP/1.1,精简而又友好的 API 接口,与主流开源 API(如:Apache HttpClient、Jetty、OkHttp 等)类似甚至拥有更高的性能。与此同时它是 Java 在 Reactive-Stream 方面的第一个生产实践,其中广泛使用了 Java Flow API,终于让 Java 标准 HTTP 类库在扩展能力等方面,满足了现代互联网的需求,是一个难得的现代 Http/2 Client API 标准的实现,Java 工程师终于可以摆脱老旧的 HttpURLConnection 了。下面模拟 Http GET 请求并打印返回内容:
清单 1. GET 请求示例
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://openjdk.java.net/"))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
Epsilon:低开销垃圾回收器
Epsilon 垃圾回收器的目标是开发一个控制内存分配,但是不执行任何实际的垃圾回收工作。它提供一个完全消极的 GC 实现,分配有限的内存资源,最大限度的降低内存占用和内存吞吐延迟时间。
Java 版本中已经包含了一系列的高度可配置化的 GC 实现。各种不同的垃圾回收器可以面对各种情况。但是有些时候使用一种独特的实现,而不是将其堆积在其他 GC 实现上将会是事情变得更加简单。
下面是 no-op GC 的几个使用场景:
- 性能测试:什么都不执行的 GC 非常适合用于 GC 的差异性分析。no-op (无操作)GC 可以用于过滤掉 GC 诱发的性能损耗,比如 GC 线程的调度,GC 屏障的消耗,GC 周期的不合适触发,内存位置变化等。此外有些延迟者不是由于 GC 引起的,比如 scheduling hiccups, compiler transition hiccups,所以去除 GC 引发的延迟有助于统计这些延迟。
- 内存压力测试:在测试 Java 代码时,确定分配内存的阈值有助于设置内存压力常量值。这时 no-op 就很有用,它可以简单地接受一个分配的内存分配上限,当内存超限时就失败。例如:测试需要分配小于 1G 的内存,就使用-Xmx1g 参数来配置 no-op GC,然后当内存耗尽的时候就直接 crash。
- VM 接口测试:以 VM 开发视角,有一个简单的 GC 实现,有助于理解 VM-GC 的最小接口实现。它也用于证明 VM-GC 接口的健全性。
- 极度短暂 job 任务:一个短声明周期的 job 任务可能会依赖快速退出来释放资源,这个时候接收 GC 周期来清理 heap 其实是在浪费时间,因为 heap 会在退出时清理。并且 GC 周期可能会占用一会时间,因为它依赖 heap 上的数据量。
- 延迟改进:对那些极端延迟敏感的应用,开发者十分清楚内存占用,或者是几乎没有垃圾回收的应用,此时耗时较长的 GC 周期将会是一件坏事。
- 吞吐改进:即便对那些无需内存分配的工作,选择一个 GC 意味着选择了一系列的 GC 屏障,所有的 OpenJDK GC 都是分代的,所以他们至少会有一个写屏障。避免这些屏障可以带来一点点的吞吐量提升。
Epsilon 垃圾回收器和其他 OpenJDK 的垃圾回收器一样,可以通过参数 -XX:+UseEpsilonGC
开启。
Epsilon 线性分配单个连续内存块。可复用现存 VM 代码中的 TLAB 部分的分配功能。非 TLAB 分配也是同一段代码,因为在此方案中,分配 TLAB 和分配大对象只有一点点的不同。Epsilon 用到的 barrier 是空的(或者说是无操作的)。因为该 GC
执行任何的 GC 周期,不用关系对象图,对象标记,对象复制等。引进一种新的 barrier-set 实现可能是该 GC 对 JVM 最大的变化。
简化启动单个源代码文件的方法
Java 11 版本中最令人兴奋的功能之一是增强 Java 启动器,使之能够运行单一文件的 Java 源代码。此功能允许使用 Java 解释器直接执行 Java 源代码。源代码在内存中编译,然后由解释器执行。唯一的约束在于所有相关的类必须定义在同一个 Java 文件中。
此功能对于开始学习 Java 并希望尝试简单程序的人特别有用,并且能与 jshell 一起使用,将成为任何初学者学习语言的一个很好的工具集。不仅初学者会受益,专业人员还可以利用这些工具来探索新的语言更改或尝试未知的 API。
如今单文件程序在编写小实用程序时很常见,特别是脚本语言领域。从中开发者可以省去用 Java 编译程序等不必要工作,以及减少新手的入门障碍。在基于 Java 10 的程序实现中可以通过三种方式启动:
- 作为
* .class
文件 - 作为
* .jar
文件中的主类 - 作为模块中的主类
而在最新的 Java 11 中新增了一个启动方式,即可以在源代码中声明类,例如:如果名为 HelloWorld.java
的文件包含一个名为 hello.World
的类,那么该命令:
$ java HelloWorld.java
也等同于:
$ javac HelloWorld.java
$ java -cp . hello.World
用于 Lambda 参数的局部变量语法
在 Lambda 表达式中使用局部变量类型推断是 Java 11 引入的唯一与语言相关的特性,这一节,我们将探索这一新特性。
从 Java 10 开始,便引入了局部变量类型推断这一关键特性。类型推断允许使用关键字 var 作为局部变量的类型而不是实际类型,编译器根据分配给变量的值推断出类型。这一改进简化了代码编写、节省了开发者的工作时间,因为不再需要显式声明局部变量的类型,而是可以使用关键字 var,且不会使源代码过于复杂。
可以使用关键字 var 声明局部变量,如下所示:
var s = "Hello Java 11";
System.out.println(s);
但是在 Java 10 中,还有下面几个限制:
- 只能用于局部变量上
- 声明时必须初始化
- 不能用作方法参数
- 不能在 Lambda 表达式中使用
Java 11 与 Java 10 的不同之处在于允许开发者在 Lambda 表达式中使用 var 进行参数声明。乍一看,这一举措似乎有点多余,因为在写代码过程中可以省略 Lambda 参数的类型,并通过类型推断确定它们。但是,添加上类型定义同时使用 @Nonnull
和 @Nullable
等类型注释还是很有用的,既能保持与局部变量的一致写法,也不丢失代码简洁。
Lambda 表达式使用隐式类型定义,它形参的所有类型全部靠推断出来的。隐式类型 Lambda 表达式如下:
(x, y) -> x.process(y)
Java 10 为局部变量提供隐式定义写法如下:
var x = new Foo();
for (var x : xs) { ... }
try (var x = ...) { ... } catch ...
为了 Lambda 类型表达式中正式参数定义的语法与局部变量定义语法的不一致,且为了保持与其他局部变量用法上的一致性,希望能够使用关键字 var
隐式定义 Lambda 表达式的形参:
(var x, var y) -> x.process(y)
于是在 Java 11 中将局部变量和 Lambda 表达式的用法进行了统一,并且可以将注释应用于局部变量和 Lambda 表达式:
@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)
低开销的 Heap Profiling
Java 11 中提供一种低开销的 Java 堆分配采样方法,能够得到堆分配的 Java 对象信息,并且能够通过 JVMTI 访问堆信息。
引入这个低开销内存分析工具是为了达到如下目的:
- 足够低的开销,可以默认且一直开启
- 能通过定义好的程序接口访问
- 能够对所有堆分配区域进行采样
- 能给出正在和未被使用的 Java 对象信息
对用户来说,了解它们堆里的内存分布是非常重要的,特别是遇到生产环境中出现的高 CPU、高内存占用率的情况。目前有一些已经开源的工具,允许用户分析应用程序中的堆使用情况,比如:Java Flight Recorder、jmap、YourKit 以及 VisualVM tools.。但是这些工具都有一个明显的不足之处:无法得到对象的分配位置,headp dump 以及 heap histogram 中都没有包含对象分配的具体信息,但是这些信息对于调试内存问题至关重要,因为它能够告诉开发人员他们的代码中发生的高内存分配的确切位置,并根据实际源码来分析具体问题,这也是 Java 11 中引入这种低开销堆分配采样方法的原因。
支持 TLS 1.3 协议
Java 11 中包含了传输层安全性(TLS)1.3 规范(RFC 8446)的实现,替换了之前版本中包含的 TLS,包括 TLS 1.2,同时还改进了其他 TLS 功能,例如 OCSP 装订扩展(RFC 6066,RFC 6961),以及会话散列和扩展主密钥扩展(RFC 7627),在安全性和性能方面也做了很多提升。
新版本中包含了 Java 安全套接字扩展(JSSE)提供 SSL,TLS 和 DTLS 协议的框架和 Java 实现。目前,JSSE API 和 JDK 实现支持 SSL 3.0,TLS 1.0,TLS 1.1,TLS 1.2,DTLS 1.0 和 DTLS 1.2。
同时 Java 11 版本中实现的 TLS 1.3,重新定义了以下新标准算法名称:
- TLS 协议版本名称:TLSv1.3
- SSLContext 算法名称:TLSv1.3
- TLS 1.3 的 TLS 密码套件名称:TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384
- 用于 X509KeyManager 的 keyType:RSASSA-PSS
- 用于 X509TrustManager 的 authType:RSASSA-PSS
还为 TLS 1.3 添加了一个新的安全属性 jdk.tls.keyLimits。当处理了特定算法的指定数据量时,触发握手后,密钥和 IV 更新以导出新密钥。还添加了一个新的系统属性 jdk.tls.server.protocols,用于在 SunJSSE 提供程序的服务器端配置默认启用的协议套件。
之前版本中使用的 KRB5 密码套件实现已从 Java 11 中删除,因为该算法已不再安全。同时注意,TLS 1.3 与以前的版本不直接兼容。
升级到 TLS 1.3 之前,需要考虑如下几个兼容性问题:
- TLS 1.3 使用半关闭策略,而 TLS 1.2 以及之前版本使用双工关闭策略,对于依赖于双工关闭策略的应用程序,升级到 TLS 1.3 时可能存在兼容性问题。
- TLS 1.3 使用预定义的签名算法进行证书身份验证,但实际场景中应用程序可能会使用不被支持的签名算法。
- TLS 1.3 再支持 DSA 签名算法,如果在服务器端配置为仅使用 DSA 证书,则无法升级到 TLS 1.3。
- TLS 1.3 支持的加密套件与 TLS 1.2 和早期版本不同,若应用程序硬编码了加密算法单元,则在升级的过程中需要修改相应代码才能升级使用 TLS 1.3。
- TLS 1.3 版本的 session 用行为及秘钥更新行为与 1.2 及之前的版本不同,若应用依赖于 TLS 协议的握手过程细节,则需要注意。
ZGC:可伸缩低延迟垃圾收集器
ZGC 即 Z Garbage Collector(垃圾收集器或垃圾回收器),这应该是 Java 11 中最为瞩目的特性,没有之一。ZGC 是一个可伸缩的、低延迟的垃圾收集器,主要为了满足如下目标进行设计:
- GC 停顿时间不超过 10ms
- 即能处理几百 MB 的小堆,也能处理几个 TB 的大堆
- 应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)
- 方便在此基础上引入新的 GC 特性和利用 colord
- 针以及 Load barriers 优化奠定基础
- 当前只支持 Linux/x64 位平台
停顿时间在 10ms 以下,10ms 其实是一个很保守的数据,即便是 10ms 这个数据,也是 GC 调优几乎达不到的极值。根据 SPECjbb 2015 的基准测试,128G 的大堆下最大停顿时间才 1.68ms,远低于 10ms,和 G1 算法相比,改进非常明显。
图 1. 回收算法停顿时间对比
本图片引用自: The Z Garbage Collector – An Introduction
不过目前 ZGC 还处于实验阶段,目前只在 Linux/x64 上可用,如果有足够的需求,将来可能会增加对其他平台的支持。同时作为实验性功能的 ZGC 将不会出现在 JDK 构建中,除非在编译时使用 configure 参数: --with-jvm-features=zgc
显式启用。
在实验阶段,编译完成之后,已经迫不及待的想试试 ZGC,需要配置以下 JVM 参数,才能使用 ZGC,具体启动 ZGC 参数如下:
-XX:+ UnlockExperimentalVMOptions -XX:+ UseZGC -Xmx10g
其中参数: -Xmx
是 ZGC 收集器中最重要的调优选项,大大解决了程序员在 JVM 参数调优上的困扰。ZGC 是一个并发收集器,必须要设置一个最大堆的大小,应用需要多大的堆,主要有下面几个考量:
- 对象的分配速率,要保证在 GC 的时候,堆中有足够的内存分配新对象。
- 一般来说,给 ZGC 的内存越多越好,但是也不能浪费内存,所以要找到一个平衡。
飞行记录器
飞行记录器之前是商业版 JDK 的一项分析工具,但在 Java 11 中,其代码被包含到公开代码库中,这样所有人都能使用该功能了。
Java 语言中的飞行记录器类似飞机上的黑盒子,是一种低开销的事件信息收集框架,主要用于对应用程序和 JVM 进行故障检查、分析。飞行记录器记录的主要数据源于应用程序、JVM 和 OS,这些事件信息保存在单独的事件记录文件中,故障发生后,能够从事件记录文件中提取出有用信息对故障进行分析。
启用飞行记录器参数如下:
-XX:StartFlightRecording
也可以使用 bin/jcmd 工具启动和配置飞行记录器:
清单 2. 飞行记录器启动、配置参数示例
$ jcmd <pid> JFR.start
$ jcmd <pid> JFR.dump filename=recording.jfr
$ jcmd <pid> JFR.stop
JFR 使用测试:
清单 3. JFR 使用示例
public class FlightRecorderTest extends Event {
@Label("Hello World")
@Description("Helps the programmer getting started")
static class HelloWorld extends Event {
@Label("Message")
String message;
}
public static void main(String[] args) {
HelloWorld event = new HelloWorld();
event.message = "hello, world!";
event.commit();
}
}
在运行时加上如下参数:
java -XX:StartFlightRecording=duration=1s, filename=recording.jfr
下面读取上一步中生成的 JFR 文件:recording.jfr
清单 4. 飞行记录器分析示例
public void readRecordFile() throws IOException {
final Path path = Paths.get("D:\\ java \\recording.jfr");
final List<RecordedEvent> recordedEvents = RecordingFile.readAllEvents(path);
for (RecordedEvent event : recordedEvents) {
System.out.println(event.getStartTime() + "," + event.getValue("message"));
}
}
动态类文件常量
为了使 JVM 对动态语言更具吸引力,Java 的第七个版本已将 invokedynamic 引入其指令集。
过 Java 开发人员通常不会注意到此功能,因为它隐藏在 Java 字节代码中。通过使用 invokedynamic,可以延迟方法调用的绑定,直到第一次调用。例如,Java 语言使用该技术来实现 Lambda 表达式,这些表达式仅在首次使用时才显示出来。这样做,invokedynamic 已经演变成一种必不可少的语言功能。
Java 11 引入了类似的机制,扩展了 Java 文件格式,以支持新的常量池:CONSTANT_Dynamic,它在初始化的时候,像 invokedynamic
指令生成代理方法一样,委托给 bootstrap 方法进行初始化创建,对上层软件没有很大的影响,降低开发新形式的可实现类文件约束带来的成本和干扰。
结束语
Java 在更新发布周期为每半年发布一次之后,在合并关键特性、快速得到开发者反馈等方面,做得越来越好。Java 11 版本的发布也带来了不少新特性和功能增强、性能提升、基础能力的全面进步和突破,本文针对其中对使用人员影响重大的以及主要的特性做了介绍。Java 12 即将到来,您准备好了吗?
本文仅代表作者个人观点,不代表其所在单位的意见,如有不足之处,还望您能够海涵。希望您能够反馈意见,交流心得,一同进步。
https://developer.ibm.com/zh/articles/the-new-features-of-java-11/
JDK13
JDK13新特性,让开发效率更快一步
JDK13到今天已经发布快2个月了,之前有零零散散的试过一些新的特性,但却没有整体的整理一下。想到作为Java开发,连使用的JDK(Java Developerment Kit)有什么特性都不清楚,实在是有些不应该,想要进阶为更有价值的JAVA开发人员,一定要跟得上JDK的最新特性。
那再来看下,这份迟来的JDK新特性一览
JDK13
所有的JDK特性都会在JEP进度中提出来和跟踪:openjdk.java.net/jeps/0
对于每个JDK版本的有什么特性在对应JDK主页中查看:openjdk.java.net/projects/jd…
JDK13主要有5个特性:
- 350: Dynamic CDS Archives 参考: www.jianshu.com/p/0b8a9d137…
- 351: ZGC: Uncommit Unused Memory 参考:www.jianshu.com/p/18fc5a042…
- 353: Reimplement the Legacy Socket API
- 354: Switch Expressions (Preview)
- 355: Text Blocks (Preview)
Dynamic CDS Archives
在JDK10中被引入的新特性,但是当时创建步骤比较繁琐。
# JDK10中需要的步骤
1. 需要指定要归档那些类 -XX:DumpLoadedClassList=classes.lst
2. 创建归档 -Xshare:dump -XX:SharedArchiveFile -XX:SharedClassListFile=classes.lst
3. 使用归档 -Xshare:on -XX:SharedArchiveFile
复制代码
在JDK13中引入新的选项,在程序退出时自动归档:
java -XX:ArchiveClassesAtExit=app.jsa -cp app.jar HelloDemo
复制代码
使用归档步骤与之前相同,默认-Xshare:on是开启的
类加载过程:
加载->验证->准备->解析->初始化->使用->卸载
- 加载:找到Class的位置,从Class位置读取Class文件内容
- 验证:文件格式的验证、元数据的验证、字节码验证和符号引用验证。
- 准备:正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。存储为JDK内部数据结构
- 解析:虚拟机将常量池中的符号引用转化为直接引用的过程,解析接口,字段解析
- 初始化:创建类
CDS的设计目的主要为了提升启动应用时的速度,class-data只需要创建一次,后续重复使用,减少了加载,验证,准备阶段。可能会有解析阶段
参考:App CDS实战
ZGC: Uncommit Unused Memory
ZGC从JDK11中被引入进来,在进行GC的时候保证更短的停顿时间,10ms以下,在JDK13中新增了归还未提交,未使用的内存给操作系统
ZGC由许多的ZPage组成,Zpage是不同大小的内存区域,分为小、中、大。当ZGC压缩内存时,Zpage被清空到ZPageCache中,ZpageCache是准备随时被用到的区域,如果被使用,会立刻从ZpageCache中移除到Zpage中,但是如果ZpageCache中的Zpage长时间未使用,则变为未提交使用的内存,后续可还给操作系统。
When ZGC compacts the heap, ZPages are freed up and inserted into a page cache, the ZPageCache.
#设置一个时间多久从ZpageCache中移除(evict)Zpage
-XX:+UnlockExperimentalVMOptions -XX:+ZUncommit -XX:ZUncommitDelay=<seconds>
复制代码
参考:ZGC完全指南
Reimplement the Legacy Socket API
JDK底层对Socket的实现非常的古老,从JDK1.0中被使用一直到现在,底层为很早的Java和C代码,对于开发JDK的人来说,非常的难以维护和Debug,因此重新实现了Socket API的接口。
-
JDK13之前,使用PlainSocketImpl
-
JDK13引入了,NioSocketImpl替换PlainSocketImpl。
来一个HelloWorld案例:
public class HelloApp {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
boolean running = true;
System.out.println("listened 8888");
while (running) {
Socket clientSocket = serverSocket.accept();
//do something with clientSocket
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
但是我们仍然可以切换为PlainSocketImpl。需配置jdk.net.usePlainSocketImpl
/Library/Java/JavaVirtualMachines/jdk-13.jdk/Contents/Home/bin/java -XX:+TraceClassLoading me/aihe/HelloApp.java | grep -i socketI
复制代码
/Library/Java/JavaVirtualMachines/jdk-13.jdk/Contents/Home/bin/java -XX:+TraceClassLoading -Djdk.net.usePlainSocketImpl me/aihe/HelloApp.java | grep -i socketI
复制代码
Switch Expressions (Preview)
引入了一个新的关键字yield用于返回switch语句的内容。最开始我们写switch语句都要在语句之前做一些初始化变量,现在可以直接得到swicth语句额返回结果
最开始的switch写法:
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalStateException("Wat: " + day);
}
复制代码
在JDK13中可以这样写:
# 没有逻辑的返回
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
# 逻辑较多的处理
String result = switch (number) {
case 1, 2:
// 逻辑代码
yield "one or two";
case 3:
// 逻辑代码
yield "three";
case 4, 5, 6:
yield "four or five or six";
default:
yield "unknown";
};
return result;
复制代码
Text Blocks (Preview)
最开始写长字符串的时候,往往要使用多个字符串拼接,一是浪费性能,而是看起来很难看。尤其写HTML字符串或者SQL语句时。
// 比如HTML
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
复制代码
现在可以写成:
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
复制代码
注意:
- 其中有个细微的区别,是开头"""之后必须另起一行,另外结尾的"""是否另起一行有不同的效果
- 注意在使用的时候每一行可能需要处理两边的空格
"""
line 1
line 2
line 3
"""
=>
"line 1\nline 2\nline 3\n"
复制代码
"""
line 1
line 2
line 3"""
=>
"line 1\nline 2\nline 3"
复制代码
最后
JDK13在一定程度上还是可以加快我们的开发速度...,最重要的是其归档特性可以大大减少我们应用的启动时间,ZGC则让我们在内存吃紧时,又带来了福音。
值得一试!
作者:Real_man
链接:https://juejin.im/post/6844903989855649800
来源:掘金
JDK14
JDK14发布了,快来看看有什么新特性吧
JDK14正式发布
2020年3月17日,JDK14正式发布。
JDK14将在4月和7月收到安全更新,然后由9月到期的非LTS版本的JDK 15取代。JDK14包括16项新功能,例如JDK Flight Recorder事件流,模式匹配和开关表达式等特征。
从JDK9之后,Oracle采用了新的发布周期:每6个月发布一个版本,每3年发布一个LTS版本。JDK14是继JDK9之后发布的第四个版本, 该版本为非LTS版本,最新的LTS版本为JDK11。
JDK14 新特性
JDK14包含了比JDK12和JDK13加在一起还多的特性。共包括16项的新特性。
新的语言特性
包括7项新特性,其中3项为正式特性,7项为非正式特性。
Switch Expressions
Switch Expressions 在 JDK 12 与 13 中都是预览状态,现在在 JDK 14 中已成为稳定特性。switch 表达式扩展了 switch 语句,使其不仅可以作为语句(statement),还可以作为表达式(expression),并且两种写法都可以使用传统的 switch 语法,或者使用简化的“case L ->”模式匹配语法作用于不同范围并控制执行流。这些更改将简化日常编码工作,并为 switch 中的模式匹配做好准备
改进NullPointerExceptions
改进 NullPointerExceptions,通过准确描述哪些变量为 null 来提高 JVM 生成的异常的可用性。该提案的作者希望为开发人员和支持人员提供有关程序为何异常终止的有用信息,并通过更清楚地将动态异常与静态程序代码相关联来提高对程序的理解。
非易失性映射的字节缓冲
非易失性映射的字节缓冲将添加新的 JDK 特定文件映射模式,该模式允许 FileChannel API 用于创建引用非易失性内存(NVM)的 MappedByteBuffer 实例。
Records语法(Preview)
Records 提供了一种紧凑的语法来声明类,以帮助开发者写出更简洁的代码,这些类是浅层不可变数据(shallowly immutable data)的透明拥有者。该特性主要用在特定领域的类,这些类主要用于保存数据,不提供领域行为。
为 instanceof 运算符引入模式匹配(Preview)
通过模式匹配,开发者可以用更简洁和更安全的方式来表达通用的程序逻辑。instanceof 运算符的模式匹配支持从对象中按条件来提取组件,此语言特性目前处于预览阶段。
文本块特性(Second Preview)
文本块特性(Text Blocks)与常见的 Python"""any input"""特性一样,它支持多行字符串文字,可以不需要使用大多数转义序列,并以一种可预测的方式自动设置字符串格式,同时可以让开发人员控制格式。虽然这不是特别复杂的特性,但对于开发中想将 HTML 代码引入 Java 来说是极大的便利,代码可读性也极大提高。目前处于第二个预览阶段。
外部内存访问 API(孵化阶段)
新增一个 API 以允许 Java 程序安全有效地访问 Java 堆之外的外部内存。
垃圾回收修改
共包括6项新特性,修改均为正式状态。
针对 G1 的 NUMA-Aware 内存分配
通过实现 NUMA-aware 内存分配,提升 G1 在大型机器上的性能。
JFR 事件流
暴露 JDK Flight Recorder 数据以进行连续监视。
移除部分垃圾回收器
- 移除CMS垃圾回收器
- 弃用 ParallelScavenge + SerialOld GC 的垃圾回收算法组合
ZGC垃圾回收期支持macOs和Windows平台
将 ZGC 垃圾回收器移植到 macOS和Windows平台。
移除包和功能
共包括2个新特性。
- 删除Pack200工具和API
- 弃用Solaris和SPARC端口
新工具
共包括1个项子新特性。处于孵化状态。
打包工具(孵化阶段)
创建一个用于打包独立 Java 应用程序的工具。
所有特性汇总
全部新特性如下:
-
305: instanceof的模式匹配(预览)
-
343: 包装工具(培养箱)
-
345: G1的NUMA感知内存分配
-
349: JFR事件流
-
352: 非易失性映射字节缓冲区
-
358: 有用的NullPointerExceptions
-
359: 记录(预览)
-
361: 开关表达式(标准)
-
362: 弃用Solaris和SPARC端口
-
363: 删除并发标记扫描(CMS)垃圾收集器
-
364: Mac OS上的ZGC
-
365: Windows上的ZGC
-
366: 弃用ParallelScavenge + SerialOld GC组合
-
367: 删除Pack200工具和API
-
368: 文本块(第二预览)
-
370: 外部存储器访问API(孵化器)
作者:samdyli的博客
链接:https://juejin.im/post/6844904099381510152
来源:掘金
JDK15
JDK15新特性详解
OpenJDK 15的新特性和变化包括:
1)外内存访问API(foreign-memory access API)
外内存访问 API 的第二个孵化器,它将使 Java 程序能够安全和有效地访问 Java 堆之外的外部内存。此 API 能够操作各种类型的外部内存,如本机、持久和托管堆。有许多 Java 程序是访问外部内存的,比如 Ignite
和MapDB
。该API将有助于避免与垃圾收集相关的成本以及与跨进程共享内存以及通过将文件映射到内存来序列化和反序列化内存内容相关的不可预测性。该Java API
目前没有为访问外部内存提供令人满意的解决方案。但是在新的提议中,API
不应该破坏JVM
的安全性。在JDK 14
中,这个功能正在经历早期的孵化阶段,在JDK 15
中还提供了改进。
2)密封类(sealed classes)的预览
与接口一样,密封类也限制其他类或接口可以扩展或实现它们。这个特性的目标包括——允许类或接口的作者来控制哪些代码负责实现、提供了比限制使用超类的访问修饰符声明方式更多选择,并通过支持对模式的详尽分析而支持模式匹配的未来发展。
3)相关支持的删除
删除对Solaris/SPARC
、Solaris/x64
和Linux/SPARC
端口的源代码和构建支持,而在JDK 14
中不赞成删除这些端口,但可在将来的版本中删除它们。许多正在开发的项目和功能(如Valhalla、Loom和Panama)需要进行重大更改以适应 CPU 架构和操作系统特定代码。放弃对Solaris
和SPARC
端口的支持将使OpenJDK
社区的贡献者加快开发新特性,从而推动平台向前发展。近年来,Solaris
和SPARC
都被Linux
操作系统和Intel
处理器所取代。
4)记录结构(Records)
记录是充当不可变数据的透明载体类,在 JDK 14 中作为早期预览进行了首次调试之后,它将被包含在 JDK 15 的第二个预览版本中。计划的目标包括设计一个面向对象的结构,表达一个简单的聚合值,帮助程序员关注建模不可变的数据,而不是扩展行为,自动实现数据驱动的方法,如如equals
和assessors
,并保留 Java 中长期存在的原则,如名义类型和迁移兼容性 。Records
(记录)可以被认为是名义元组。
5)数字签名算法
基于Edwards-Curve
数字签名算法(EdDSA-Edwards-Curve Digital Signature Algorithm)的加密签名。EdDSA
是一种现代的椭圆曲线方案,具有 JDK 中现有签名方案的优点。EdDSA
将只在SunEC
提供商中实现。EdDSA
与其他签名方案相比,具有更高的安全性和性能,因此备受关注;它已经在OpenSSL
和BoringSSL
等加密库中得到支持。
6)套接字的更新实现
通过将java.net.datagram.Socket
和java.net.MulticastSocket API
的底层实现替换为更简单、更现代的实现来重新实现遗留的DatagramSocket API
。新的实现:
1.易于调试和维护;
2.与Project Loom中正在探索的虚拟线程协同。
新的计划是 JDK Enhancement Proposal 353
的后续,该方案重新实现了遗留的套接字 API。java.net.datagram.Socket
和java.net.MulticastSocket
的当前实现可以追溯到 JDK 1.0,那时 IPv6 还在开发中。因此,当前的多播套接字实现尝试调和 IPv4 和 IPv6 难以维护的方式。
7)禁用偏向/偏置锁定
在默认情况下禁用偏向锁定,并弃用所有相关命令行选项。目标是确定是否需要继续支持偏置锁定的高维护成本的遗留同步优化,HotSpot
虚拟机使用该优化来减少非竞争锁定的开销。尽管某些 Java 应用程序在禁用偏向锁后可能会出现性能下降,但偏向锁的性能提高通常不像以前那么明显。
8)instanceof模式匹配
此为第二个预览版,之前是 JDK 14 中的首次预览。模式匹配允许程序中的通用逻辑(主要是有条件地从对象中提取组件)得到更精确的表达。像Haskell
和c#
这样的语言已经包含了模式匹配,因为它的简易性和安全性。
9)隐藏类(Hidden classes)
即不能被其他类的字节码直接使用的类,是为在运行时生成类并通过反射间接使用类的框架使用的。隐藏类可以定义为访问控制嵌套的成员,并且可以独立于其他类卸载。该提议将通过支持一个标准 API 来定义不可发现且生命周期有限的隐藏类,从而提高 JVM 上所有语言的效率。JDK 内部和外部的框架将能够动态生成类,而这些类可以定义隐藏类。许多构建在 JVM 上的语言都依赖动态类生成来获得灵活性和效率。这个提议的目标包括:允许框架将类定义为无法发现的框架实现细节,这样它们就不能被其他类链接,也不能通过反射被发现;支持扩展带有不可发现类的访问控制嵌套;并支持主动卸载不可发现的类,因此框架可以根据需要灵活地定义多个类。另一个目标是弃用非标准API misc.Unsafe::defineAnonymousClass
,目的是为了在将来的版本中删除。另外, Java 语言不会因为这个建议而改变。
10)ZGC产品化
在这个提案下,Z垃圾收集器(ZGC-Z Garbage Collector)将从一个实验特性升级为产品。 ZGC 集成到2018年9月发布的JDK 11中,是一个可扩展的、低延迟的垃圾收集器。 ZGC 是作为一种实验性的功能引入的,因为 Java 开发人员决定应该小心地、逐步地引入这种规模和复杂性的特性。从那时起,添加了许多改进,从并发类卸载、未使用内存的解除提交、对类数据共享的支持到改进的 NUMA 感知和多线程堆预处理。此外,最大堆大小从4TB增加到16TB。支持的平台包括Linux
、Windows
和MacOS
。
11)文本块
JDK 14
和JDK 13
中都预览版文本块,它旨在简化编写 Java 程序的任务,方法是简化表达跨越几行源代码的字符串,同时在常见情况下避免转义序列。文本块是一个多行字符串文字,它可以避免使用大多数转义序列、自动以可预测的方式格式化字符串,并在需要时为开发人员提供对格式的控制。文本块建议的一个目标是增强 Java 程序中表示用非J Java 语言编写的代码的字符串的可读性。另一个目标是通过规定任何新构造都可以将相同的字符串集表示为字符串文字,解释相同的转义序列,并以与字符串文字相同的方式操作,从而支持字符串文字的迁移。OpenJDK 开发人员希望添加转义序列来管理显式的空格和换行控件。
12)LPT GC正式可用
Shenandoah
低暂停时间(low-pause-time)垃圾收集器将成为一个生产特性,不再处于实验阶段。它在一年前被集成到JDK 12中。
13)删除Nashorn
2014年3月在jdk8中首次亮相的Nashorn
被移除,由于其被GraalVM
等技术淘汰。OpenJDK 15 提议要求删除Nashorn APIs
和用于调用Nashorn
的jjs
命令行工具。
14)RMI Activation进入不推荐期
不推荐 RMI 激活机制,以便将来删除。RMI 激活机制是 RMI 中一个过时的部分,自 Java 8 以来一直是可选的。RMI 激活机制增加了持续的维护负担。RMI 的其他部分将不被弃用。
JDK 15的早期访问版本可以在java.jdk.net
网站中找到。JDK 15将是一个短期的特性发布,根据 Oracle 的6个月发布周期,它将被支持6个月。下一个长期支持(LTS-long-term support)版本是JDK 17,预计将于2021年9月发布,它将获得几年的支持。当前的LTS版本是JDK 11,是于2018年9月发布。
https://www.w3cschool.cn/article/a4329ef940f3a8
JDK 15 Release Notes
The following sections are included in these Release Notes:
Introduction
These notes describe important changes, enhancements, removed APIs and features, deprecated APIs and features, and other information about JDK 15 and Java SE 15. In some cases, the descriptions provide links to additional detailed information about an issue or a change. This page does not duplicate the descriptions provided by the Java SE 15 ( JSR 390) Platform Specification, which provides informative background for all specification changes and might also include the identification of removed or deprecated APIs and features not described here. The Java SE 15 ( JSR 390) specification provides links to:
-
Annex 1: The complete Java SE 15 API Specification.
-
Annex 2: An annotated API specification showing the exact differences relative to Java SE 15. Informative background for these changes may be found in the list of approved Change Specification Requests for this release.
-
Annex 3: Java SE 15 Editions of The Java Language Specification and The Java Virtual Machine Specification. . The Java SE 15 Editions contain all corrections and clarifications made since the Java SE 14 Editions, as well as additions for new features.
You should be aware of the content in that document as well as the items described in this page.
The descriptions on this Release Note page also identify potential compatibility issues that you might encounter when migrating to JDK 15. The Kinds of Compatibility page on the OpenJDK wiki identifies three types of potential compatibility issues for Java programs used in these descriptions:
-
Source: Source compatibility preserves the ability to compile existing source code without error.
-
Binary: Binary compatibility is defined in The Java Language Specification as preserving the ability to link existing class files without error.
-
Behavioral: Behavioral compatibility includes the semantics of the code that is executed at runtime.
See CSRs Approved for JDK 15 for the list of CSRs closed in JDK 15 and the Compatibility & Specification Review (CSR) page on the OpenJDK wiki for general information about compatibility.
IANA Data 2020a
JDK 15 contains IANA time zone data version 2020a. For more information, refer to Timezone Data Versions in the JRE Software.
What's New in JDK 15 - New Features and Enhancements
This section describes some of the enhancements in Java SE 15 and JDK 15. In some cases, the descriptions provide links to additional detailed information about an issue or a change. The APIs described here are those that are provided with the Oracle JDK. It includes a complete implementation of the Java SE 15 Platform and additional Java APIs to support developing, debugging, and monitoring Java applications. Another source of information about important enhancements and new features in Java SE 15 and JDK 15 is the Java SE 15 ( JSR 390) Platform Specification, which documents the changes to the specification made between Java SE 14 and Java SE 15. This document includes descriptions of those new features and enhancements that are also changes to the specification. The descriptions also identify potential compatibility issues that you might encounter when migrating to JDK 15.
java.lang.CharSequence
has been updated in this release to define a default isEmpty
method that tests if a character sequence is empty. Testing for, and filtering out, empty String
s and other CharSequence
s is a common occurrence in code and CharSequence::isEmpty
can be used as a method reference. Classes that implement java.lang.CharSequence
and another interface that defines isEmpty
method should be aware of this addition as they may need to be modified to override the isEmpty
method.
This release upgrades Unicode support to 13.0, which includes the following:
- The
java.lang.Character
class supports Unicode Character Database of 13.0 level, which 13.0 adds 5,930 characters, for a total of 143,859 characters. These additions include 4 new scripts, for a total of 154 scripts, as well as 55 new emoji characters. - The
java.text.Bidi
andjava.text.Normalizer
classes support 13.0 level of Unicode Standard Annexes, #9 and #15, respectively. - The
java.util.regex
package supports Extended Grapheme Clusters based on 13.0 level of Unicode Standard Annex #29 For more detail about Unicode 13.0, refer to the Unicode Consortium's release note.
JEP 371 introduces hidden classes in Java 15. Hidden classes have the following implications to existing code:
-
Class::getName
traditionally returns a binary name, but for a hidden class it returns a string that contains an ASCII forward slash (/
) and is therefore not a binary name. Programs that assume the returned string is a binary name might need to be updated to handle hidden classes. That said, the longstanding practice ofUnsafe::defineAnonymousClass
was to define classes whose names were not binary names, so some programs may already handle such names successfully. -
Class::descriptorString
andMethodType::descriptorString
returns a string that contains a ASCII dot (.
) for a hidden class and therefore is not a type descriptor conforming to JVMS 4.3. Programs that assume the returned string is a type descriptor that conforms to JVMS 4.3 might need to be updated to handle hidden classes. -
Class::getNestMembers
is changed to not throw an exception when it fails to validate a nest membership of any member listed inNestMembers
attribute. Instead,Class::getNestMembers
returns the nest host and the members listed in the host'sNestMembers
attribute that are successfully resolved and determined to have the same nest host as this class. (This means it may return fewer members that listed inNestMembers
attribute.) Existing code that expectsLinkageError
when there is a bad nest membership might be impacted. -
The nestmate test in the JVM is changed to throw only
IllegalAccessError
when the nest membership is invalid. Some historical understanding is necessary:
- In Java 8, every access control failure was signaled with
IllegalAccessError
(IAE). Moreover, if a given access check failed with IAE once, then the same check would fail with IAE every time. - In Java 11, the introduction of nest mates (JEP 181) meant that an access control failure could be signaled either with
IllegalAccessError
or, if nest membership was invalid,LinkageError
. Still, if a given access check failed with a specific exception, then the same check would always fail with the same exception. - In Java 15, the introduction of
Lookup::defineHiddenClass
implies that the nest host of the lookup class must be determined eagerly, when the hidden class is defined as a nestmate of the lookup class. BothLookup::defineHiddenClass
andClass::getNestHost
both determine the nest host of a class in a more resilient manner than the JVM did in Java 11; namely, the API simply treats a class as self-hosted if its purported nest membership is invalid. For consistency with the API, the JVM no longer throwsLinkageError
when a class's nest membership is invalid, and instead treats the class as self-hosted. This means that the JVM only throws IAE from access control (because a self-hosted class will not permit any other class to access its private members). This is the behavior expected by the vast majority of user code.
- JVM TI
GetClassSignature
returns a string that contains a ASCII dot (.
) for a hidden class. JVM TI agents might need updating for hidden classes if they assume the returned string fromGetClassSignature
is a type descriptor conforming to JVMS 4.3.
A new JDK-specific socket option SO_INCOMING_NAPI_ID
has been added to jdk.net.ExtendedSocketOptions
in this release. The socket option is Linux specific and allows applications to query the NAPI (New API) ID of the underlying device queue associated with its socket connection and take advantage of the Application Device Queue (ADQ) feature of high performance Network Interface Card (NIC) devices.
The TreeMap class now provides overriding implementations of the putIfAbsent
, computeIfAbsent
, computeIfPresent
, compute
, and merge
methods. The new implementations provide a performance improvement. However, if the function provided to the compute-
or merge
methods modifies the map, ConcurrentModificationException may be thrown, because the function that is provided to these methods is prohibited from modifying the map. If a ConcurrentModificationException occurs, the function must either be changed to avoid modifying the map, or the surrounding code should be rewritten to replace uses of the compute-
and merge
methods with conventional Map methods such as get
and put
.
See JDK-8227666 for further information.
JMX supports (explicit) remote network access through the configuration of two network ports (either from the command line or in a property file), by setting the following properties:
com.sun.management.jmxremote.port=<port#>
com.sun.management.jmxremote.rmi.port=<port#>
Note: If it is not specified, the second port will default to the first.
A third local port is also opened to accept (local) JMX connections. This port previously had its number selected at random, which could cause port collisions.
However, it is now possible to configure the third JMX port (local only) by using:com.sun.management.jmxremote.local.port=<port#>
A new -r <port>
option has been added to the jstatd
command to specify the RMI connector port number. If a port number is not specified, a random available port is used.
A new integer option gz
has been added to the GC.heap_dump
diagnostic command. If it is specified, it will enable the gzip compression of the written heap dump. The supplied value is the compression level. It can range from 1 (fastest) to 9 (slowest, but best compression). The recommended level is 1.
Text blocks have been added to the Java language. A text block is a multi-line string literal that avoids the need for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over the format when desired.
Three new options have been added to the jhsdb
command for the debugd mode:
-
--rmiport <port>
is used to specify a RMI connector port number. If a port number is not specified, a random available port is used. -
--registryport <port>
is used to specify a RMI registry port number. This option overrides the system propertysun.jvm.hotspot.rmi.port
. If a port number is not specified, the system property is used. If the system property is not set, the default port 1099 is used. -
--hostname <hostname>
is used to specify a RMI connector host name. The value could be a hostname or an IPv4/IPv6 address. This option overrides the system propertyjava.rmi.server.hostname
. If a host name not specified, the system property is used. If the system property is not set, a system host name is used.
The Oracle JDK installer for Windows provides java.exe
, javaw.exe
, javac.exe
, and jshell.exe
commands in a system location so that users can run Java applications without needing to provide the path to the Oracle JDK's installation folder.
A new -revCheck
option has been added to the jarsigner
command to enable revocation checking of certificates.
The keytool
and jarsigner
tools have been updated to warn users about weak cryptographic algorithms being used before they are disabled. In this release, the tools issue warnings for the SHA-1 hash algorithm and 1024-bit RSA/DSA keys.
The SunJCE provider has been enhanced to support HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, and HmacSHA3-512. Implementations for these algorithms are available under the Mac and KeyGenerator services. The Mac service generates the keyed-hash and the KeyGenerator service generates the key for the Mac.
Two new system properties have been added to customize the TLS signature schemes in JDK. jdk.tls.client.SignatureSchemes
has been added for the TLS client side, and jdk.tls.server.SignatureSchemes
has been added for the server side.
Each system property contains a comma-separated list of supported signature scheme names specifying the signature schemes that could be used for the TLS connections.
The names are described in the Java Security Standard Algorithm Names Specification section of the Java Platform, Standard Edition Security Developer’s Guide.
The "certificate_authorities" extension is an optional extension introduced in TLS 1.3. It is used to indicate the certificate authorities (CAs) that an endpoint supports and should be used by the receiving endpoint to guide certificate selection.
With this JDK release, the "certificate_authorities" extension is supported for TLS 1.3 in both the client and the server sides. This extension is always present for client certificate selection, while it is optional for server certificate selection.
Applications can enable this extension for server certificate selection by setting the jdk.tls.client.enableCAExtension
system property to true
. The default value of the property is false
.
Note that if the client trusts more CAs than the size limit of the extension (less than 2^16 bytes), the extension is not enabled. Also, some server implementations do not allow handshake messages to exceed 2^14 bytes. Consequently, there may be interoperability issues when jdk.tls.client.enableCAExtension
is set to true
and the client trusts more CAs than the server implementation limit.
The 'canonicalize' flag in the krb5.conf file is now supported by the JDK Kerberos implementation. When set to true, RFC 6806 name canonicalization is requested by clients in TGT requests to KDC services (AS protocol). Otherwise, and by default, it is not requested.
The new default behavior is different from JDK 14 and previous releases where name canonicalization was always requested by clients in TGT requests to KDC services (provided that support for RFC 6806 was not explicitly disabled with the sun.security.krb5.disableReferrals system or security properties).
The support for the Kerberos MSSFU extensions [1] is now extended to cross-realm environments.
By leveraging on the Kerberos cross-realm referrals enhancement, introduced in the context of JDK-8215032, the 'S4U2Self' and 'S4U2Proxy' extensions may be used to impersonate user and service principals located on different realms.
[1] - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94
Removed Features and Options
This section describes the APIs, features, and options that were removed in Java SE 15 and JDK 15. The APIs described here are those that are provided with the Oracle JDK. It includes a complete implementation of the Java SE 15 Platform and additional Java APIs to support developing, debugging, and monitoring Java applications. Another source of information about important enhancements and new features in Java SE 15 and JDK 15 is the Java SE 15 ( JSR 390) Platform Specification, which documents changes to the specification made between Java SE 14 and Java SE 15. This document includes the identification of removed APIs and features not described here. The descriptions below might also identify potential compatibility issues that you could encounter when migrating to JDK 15. See CSRs Approved for JDK 15 for the list of CSRs closed in JDK 15.
In this release, in conjunction with the removal of the Solaris port in JEP381 (JDK-8241787 ), the JDK-specific socket option jdk.net.ExtendedSocketOptions.SO_FLOW_SLA
, which is only relevant to sockets on Solaris, and its supporting classes SocketFlow
and SocketFlow.Status
, have been removed.
The RMI static stub compiler rmic
has been removed. The rmic
tool is obsolete and has been deprecated for removal since JDK 13.
The terminally deprecated constant javax.management.remote.rmi.RMIConnectorServer.CREDENTIAL_TYPE
has been removed. A filter pattern can be specified instead by using RMIConnectorServer.CREDENTIALS_FILTER_PATTERN
.
The Nashorn JavaScript script engine, its APIs, and the jjs
tool have been removed. The engine, the APIs, and the tool were deprecated for removal in Java 11 with the express intent to remove them in a future release.
The VM option UseAdaptiveGCBoundary
is obsolete. Use of this option will produce an obsolete option warning but will otherwise be ignored.
This option was previously disabled by default, and enabling it only had an effect when also using -XX:+UseParallelGC
. Enabling it was intended to provide a performance benefit for some applications. However, it has been disabled by default for a long time because of crashes and performance regressions.
The following expired Comodo root CA certificate has been removed from the cacerts
keystore:
+ alias name "addtrustclass1ca [jdk]"
Distinguished Name: CN=AddTrust Class 1 CA Root, OU=AddTrust TTP Network, O=AddTrust AB, C=SE
The following expired DocuSign root CA certificate has been removed from the cacerts
keystore:
+ alias name "keynectisrootca [jdk]"
Distinguished Name: CN=KEYNECTIS ROOT CA, OU=ROOT, O=KEYNECTIS, C=FR
The implementation of the deprecated SSLSession.getPeerCertificateChain()
method has been removed from the JDK in the SunJSSE provider and the HTTP client implementation. The default implementation of this method has been changed to throw UnsupportedOperationException.
SSLSession.getPeerCertificateChain()
is a deprecated method and will be removed in a future release. To mitigate the removal compatibility impact, applications should use the SSLSession.getPeerCertificates()
method instead. For service providers, please remove this method from the existing implementation, and do not support this method in any new implementation.
The legacy SunJSSE provider name, "com.sun.net.ssl.internal.ssl.Provider" has been removed and should no longer be used. The "SunJSSE" name should be used instead. For example, SSLContext.getInstance("TLS", "SunJSSE")
.
Deprecated Features and Options
Additional sources of information about the APIs, features, and options deprecated in Java SE 15 and JDK 15 include:
- The Deprecated API page identifies all deprecated APIs including those deprecated in Java SE 15.
- The Java SE 15 ( JSR 390) specification specification documents changes to the specification made between Java SE 14 and Java SE 15 that include the identification of deprecated APIs and features not described here.
- JEP 277: Enhanced Deprecation provides a detailed description of the deprecation policy. You should be aware of the updated policy described in this document.
You should be aware of the contents in those documents as well as the items described in this release notes page.
The descriptions of deprecated APIs might include references to the deprecation warnings of forRemoval=true
and forRemoval=false
. The forRemoval=true
text indicates that a deprecated API might be removed from the next major release. The forRemoval=false
text indicates that a deprecated API is not expected to be removed from the next major release but might be removed in some later release.
The descriptions below also identify potential compatibility issues that you might encounter when migrating to JDK 15. See CSRs Approved for JDK 15 for the list of CSRs closed in JDK 15.
The RMI Activation mechanism has been deprecated and may be removed in a future version of the platform. RMI Activation is an obsolete part of RMI that has been optional since Java 8. It allows RMI server JVMs to be started ("activated") upon receipt of a request from a client, instead of requiring RMI server JVMs to be running continuously. Other parts of RMI are not deprecated. See JEP 385 for further information.
After an upgrade of the macOS SDK used to build the JDK, the behavior of the apple.awt.brushMetalLook
and textured
Swing properties has changed. When these properties are set, the title of the frame is still visible. It is recommended that the apple.awt.transparentTitleBar
property be set to true
to make the title of the frame invisible again. The apple.awt.fullWindowContent
property can also be used.
Please note that Textured window
support was implemented by using the NSTexturedBackgroundWindowMask
value of NSWindowStyleMask
. However, this was deprecated in macOS 10.12 along with NSWindowStyleMaskTexturedBackground
, which was deprecated in macOS 10.14.
For additional information, refer to the following documentation:
-
apple.awt.brushMetalLook
: https://developer.apple.com/documentation/appkit/nstexturedbackgroundwindowmask?language=objc -
apple.awt.transparentTitleBar
: https://developer.apple.com/documentation/appkit/nswindow/1419167-titlebarappearstransparent?language=objc -
apple.awt.fullWindowContent
: https://developer.apple.com/documentation/appkit/nsfullsizecontentviewwindowmask
The VM option ForceNUMA
is deprecated. Use of this option will produce a deprecation warning. This option will be removed in a future release.
This option has always been disabled by default. It exists to support testing of NUMA-related code paths when running on a single node / UMA platform.
Biased locking has been disabled by default in this release. In addition, the VM option UseBiasedLocking
along with the VM options BiasedLockingStartupDelay
, BiasedLockingBulkRebiasThreshold
, BiasedLockingBulkRevokeThreshold
, BiasedLockingDecayTime
and UseOptoBiasInlining
have been deprecated. The options will continue to work as intended but will generate a deprecation warning when they are used.
Biased locking might affect performance on applications that exhibit significant amounts of uncontended synchronization, such as applications that rely on older Java Collections APIs that synchronize on every access. Hashtable
and Vector
are examples of these APIs. Use -XX:+BiasedLocking
on the command line to re-enable biased locking. Report any significant performance regressions to Oracle with biased locking disabled.
The SunEC crypto provider no longer advertises curves that are not implemented by using modern formulas and techniques. Arbitrary and named curves, listed at the bottom of this note, are disabled. Commonly used named curves, secp256r1, secp384r1, secp521r1, x25519, and x448, remain supported and enabled by SunEC because they use modern techniques. Applications that still require the disabled curves from the SunEC provider can re-enable them by setting the System property jdk.sunec.disableNative
to false
. For example: java -Djdk.sunec.disableNative=false ...
.
If this property is set to any other value, the curves will remain disabled. Exceptions thrown when the curves are disabled will contain the message Legacy SunEC curve disabled
, followed by the name of the curve. Methods affected by the change are KeyPair.generateKeyPair()
, KeyAgreement.generateSecret()
, Signature.verify()
, and Signature.sign()
. These methods throw the same exception class they had before when the curve was not supported.
The following curves are disabled: secp112r1, secp112r2, secp128r1, secp128r2, secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1 brainpoolP320r1, brainpoolP384r1, brainpoolP512r1
The ContentSigner
and ContentSignerParameters
classes in the com.sun.jarsigner
package support alternative signers and have been deprecated with forRemoval=true
. When the -altsigner
or -altsignerpath
options are specified, the jarsigner
tool produces a warning that these options are deprecated and will be removed.
Other notes
It has been found that some Windows GDI functions don't support all types of Java heap memory allocation schemes. This problem can cause repaint issues and printing bugs. It has been worked around by allocating temporary buffers off heap.
See: https://support.microsoft.com/en-us/help/4567569/gdi-apis-may-fail-when-large-pages-or-vad-spanning-is-used
When it is interrupted, the implementation of the java.awt.Robot.delay()
method has been changed to complete with the interrupt status set.
If a thread is interrupted while waiting in the java.awt.Robot.delay()
method, then this method returns immediately with the interrupt status set. If the interrupted status is already set, this method returns immediately with the interrupt status set.
When setting a serialization filter by using java.io.ObjectInputStream.setObjectInputFilter
the method must be called before reading any objects from the stream. If the methods readObject
or readUnshared
are called, the setObjectInputFilter
method throws IllegalStateException
.
The implementation of String.substring
and related methods stripLeading
and stripTrailing
have changed in this release to avoid redundantly creating a new empty String. This may impact code that depends on unspecified behaviour and the identity of empty sub-strings.
Lookup::defineClass
is specified to throw LinkageError
if a linkage error occurs, but the implementation was not actually linking the class. In this release, the implementation has been changed to link the class before returning, so conforming to the specification. If Lookup::defineClass
is called to define a class that fails linking, LinkageError
will be thrown.
Previously, DatagramChannel::disconnect
threw an IOException
while DatagramSocket::disconnect
did not. As a result, the DatagramChannel::socket
adapter, which calls DatagramChannel::disconnect
, catches the thrown IOException
and rethrows it as an Error
. However, this was undocumented behavior and not user-friendly.
The DatagramChannel::socket
adapter has been changed to throw an UncheckedIOException
, and the specification of DatagramSocket::disconnect
has been updated to document that an implementation may now throw an UncheckedIOException
. This ensures consistency in behavior between DatagramSocket
, DatagramChannel
, and DatagramChannel::socket
adapter.
During the setup of new connections, java.net.http.HttpClient
now uses the default set of protocols provided by the SSLContext
when negotiating the TLS handshake. In the absence of any SSLParameter
s explicitly supplied to the HttpClient.builder
, the HttpClient
has been updated to no longer override any default-selected protocols in the SSLContext. As a result, the actual TLS version that is negotiated might differ from that of previous releases, or it might even succeed or fail to negotiate when it previously might not have.
In this release, the behavior of InetAddress.getAllByName
has been modified when the alternative hosts file name service is selected .
The JDK allows specifying an alternative host's file name service by using the jdk.net.hosts.file
system property. The implementation of the alternative name service has been changed to take into account the values of the java.net.preferIPv4Stack
and java.net.preferIPv6Addresses
system properties. This affects the results returned by InetAddress.getAllByName
when the host's file name service is selected. For details about java.net.preferIPv4Stack
and java.net.preferIPv6Addresses
, see Networking Properties in the API documentation.
In this release, the default port number for a datagram packet has been changed to 0. Previously, this value was -1, which was undocumented. The port can be retrieved by using DatagramPacket::getPort
.
In this release, some of the one-way byte-to-char mappings have been aligned with the preferred mappings provided by the Unicode Consortium.
DecimalFormat/DecimalFormatSymbols classes are now capable of dealing with grouping separators for currency values. For example, the monetary grouping separator for the German language used in Austria (the de-AT locale) is '.', whereas the monetary grouping separator in other German locales is ' '.
java.time.format.DateTimeFormatter.localizedBy(Locale)
method now honors the default locale values, such as Chronology
and/or DecimalStyle
of the specified locale argument.
For example, in previous JDK releases:
jshell> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.localizedBy(Locale.forLanguageTag("fa"))
.format(LocalDate.now())
$3 ==> "جمعه 1 مهٔ 2020"
the numbers are in Arabic (Western) numerals.
In JDK 15:
jshell> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.localizedBy(Locale.forLanguageTag("fa"))
.format(LocalDate.now())
$3 ==> "جمعه ۱ مهٔ ۲۰۲۰"
the numbers are in Extended Arabic-Indic numerals because it is the default numbering system for the Farsi locale.
java.time.temporal.ValueRange.of()
methods are now correctly throwing an InvalidArgumentException on given invalid arguments. For example, of(5, 2, 10)
which is invalid because the minimum
is greater than the smallest maximum
, now throws the exception.
InflaterOutputStream(OutputStream out, Inflater infl, int bufLen)
allows for specifying the decompressor and buffer size to be used.
InflaterOutputStream.write(byte[] b, int off, int len)
was writing data using a max buffer size of 512 bytes.
Starting with JDK 15 the buffer size specified via InflaterOutputStream(OutputStream out, Inflater infl, int bufLen)
will be used in calls to InflaterOutputStream.write(byte[] b, int off, int len)
. If the buffer size is not specified when invoking the InflaterOutputStream
constructor, it will default to 512 bytes.
The Java regular expression engine supports the case insensitive mode. When this mode is turned on, the engine is supposed to match the input text without regard to the case of the characters it consists of.
However, the current implementation of matching against some named character classes (those that are encoded with \p{name} or \P{name} constructs) fails to respect the case insensitive mode.
This fix makes these character classes behave consistently with respect to case sensitivity. When the regular expression engine operates in the case insensitive mode, the named character classes will match the input characters without regard to their case: lower case, upper case, or title case.
The preferred way to copy a collection is to use a "copy constructor." For example, to copy a collection into a new ArrayList, one would write new ArrayList<>(collection)
. In certain circumstances, an additional, temporary copy of the collection's contents might be made in order to improve robustness. If the collection being copied is exceptionally large, then the application should be (aware of/monitor) the significant resources required involved in making the copy.
Locale data based on Unicode Consortium's CLDR has been upgraded to their version 37. For the detailed locale data changes, please refer to the Unicode Consortium's CLDR release notes:
English time zone names provided by the CLDR locale provider are now correctly synthesized following the CLDR spec, rather than substituted from the COMPAT provider. For example, SHORT style names are no longer synthesized abbreviations of LONG style names, but instead produce GMT offset formats.
jpackage cannot create packages on macOS that are suitable for notarization.
A number of flags controlling inlining in the C1 and C2 compilers have been split up into separate flags. The C2 compiler keeps the flags with the old names, and the C1 compiler gets the new flags.
Old flags now only controlling C2
- MaxInlineLevel
- MaxRecursiveInlineLevel
- MaxInlineSize
- MaxTrivialSize
- InlineSmallCode
- FreqInlineSize
New flags for C1 that replace the old ones
- C1MaxInlineLevel
- C1MaxRecursiveInlineLevel
- C1MaxInlineSize
- C1MaxTrivialSize
Deprecation
If the old flags are used in a JDK build without the C2 compiler, a deprecation warning will be printed.
The default heap region size calculation has been changed to return larger regions by default. The calculation still aims to have 2048 regions, but two aspects have changed:
- Only the maximum heap size is considered. The old calculation also took the initial heap size into consideration, but this can give unexpected behavior when no heap size is set.
- The region size is rounded up to the nearest power of 2 instead of down. This will return larger region sizes in cases where the maximum heap size is not a power of 2.
These changes improve startup and runtime performance.
The Z Garbage Collector (ZGC) is now ready for use in production and no longer marked as an experimental feature. ZGC is enabled by using the -XX:+UseZGC
command-line option (using -XX:+UnlockExperimentalVMOptions
is no longer needed).
See JEP 377 for more details.
-XX:+UseLargePages has no effect on Windows in this release. It was found that GDI APIs used by java2d don't support large pages. The JVM detects this problem and both warns about this and reverts to using small pages. See: https://support.microsoft.com/en-us/help/4567569/gdi-apis-may-fail-when-large-pages-or-vad-spanning-is-used
-XX:+UseNUMAInterleaving has no effect on Windows in this release. It was found that GDI APIs used by java2d don't support the memory reservation scheme used for NUMA interleaving. The JVM detects this problem and both warns about this and turns off NUMA interleaving. See: https://support.microsoft.com/en-us/help/4567569/gdi-apis-may-fail-when-large-pages-or-vad-spanning-is-used
The way that field layout is computed has been changed, with more aggressive optimizations to avoid unused gaps in instances. These new optimizations can be disabled by using a new VM option -XX:-UseEmptySlotsInSupers
.
For a limited time, it is possible to continue to use the old code to compute field layout with a new VM option -XX:-UseNewFieldLayout
. However, this option has been deprecated in JDK 15 and the old code will be removed in a future release.
The default of the flag ShowCodeDetailsInExceptionMessages was changed to 'true'. The helpful NullPointerException messages of JEP 358 are now printed by default. The messages contain snippets of the code where the NullPointerException was raised.
App deployers should double check the output of their web applications and similar usage scenarios. The NullPointerException message could be included in application error messages or be displayed by other means in the app. This could give remote attackers valuable hints about a potential vulnerable state of the software components being used.
An example message is 'Cannot read field "c" because "a.b" is null'. The attacker knows that field b of a contains null which might be unintended and offer an opportunity for an attack. For more details of what the message can contain see the above mentioned JEP 358.
Signature.getParameters() and SignatureSpi.engineGetParameters() may return null if the underlying provider does not support returning the parameters as AlgorithmParameters. For further details, see the Signature and SignatureSpi method descriptions.
The SunPKCS11 security provider can now be initialized with NSS when FIPS-enabled external modules are configured in the Security Modules Database (NSSDB). Before this change, when such a library was configured for NSS in non-FIPS mode, the SunPKCS11 provider would throw a RuntimeException with the message "FIPS flag set for non-internal module".
This change allows the JDK to work properly with recent NSS releases in GNU/Linux operating systems when the system-wide FIPS policy is turned on.
In JDK 11 and later, javax.net.ssl.SSLEngine
by default used client mode when handshaking. As a result, the set of default enabled protocols may differ to what is expected. SSLEngine
would usually be used in server mode. From this JDK release onwards, SSLEngine
will default to server mode. The javax.net.ssl.SSLEngine.setUseClientMode(boolean mode)
method may be used to configure the mode.
Pattern matching for the instanceof
operator is a preview feature of the Java language in JDK 15. Pattern matching allows common logic in a Java program to be expressed more concisely and safely, namely the conditional extraction of components from objects. Preview features must not be used in production, but feedback from Java developers on the usability of preview features is welcome.
The Standard Doclet no longer generates pre-compressed index files. Decisions about compression are now left to the underlying means of delivery (for example, application layer protocols such as HTTP).
Differences Between Oracle JDK and Oracle's OpenJDK
Although we have stated the goal to have OpenJDK and Oracle JDK binaries be as close to each other as possible there remain several differences between the two options.
The current differences are:
- Oracle JDK offers "installers" (
msi
,rpm
,deb
, etc.) which not only place the JDK binaries in your system but also contain update rules and in some cases handle some common configurations like set common environmental variables (such as, JAVA_HOME in Windows) and establish file associations (such as, usejava
to launch.jar
files). OpenJDK is offered only as compressed archive (tar.gz
or.zip
). - Usage Logging is only available in Oracle JDK.
- Oracle JDK requires that third-party cryptographic providers be signed with a Java Cryptography Extension (JCE) Code Signing Certificate. OpenJDK continues allowing the use of unsigned third-party crypto providers.
- The output of
java -version
is different. Oracle JDK returnsjava
and includes the Oracle-specific identifier. OpenJDK returns OpenJDK and does not include the Oracle-specific identifier. - Oracle JDK is released under the OTN License. OpenJDK is released under GPLv2wCP. License files included with each will therefore be different.
- Oracle JDK distributes FreeType under the FreeType license and OpenJDK does so under GPLv2. The contents of
\legal\java.desktop\freetype.md
is therefore different. - Oracle JDK has Java cup and steam icons and OpenJDK has Duke icons.
- Oracle JDK source code includes "ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms." Source code distributed with OpenJDK refers to the GPL license terms instead.
https://www.oracle.com/java/technologies/javase/15-relnote-issues.html#NewFeature