目录
[二、Dynamic Class-File Constants类文件新添的一种结构](#二、Dynamic Class-File Constants类文件新添的一种结构)
[三、局部变量类型推断(var "关键字")](#三、局部变量类型推断(var ”关键字”))
[1. 新的本机不可修改集合API](#1. 新的本机不可修改集合API)
[2. Stream 加强](#2. Stream 加强)
[3. String 加强](#3. String 加强)
[4. Optional 加强](#4. Optional 加强)
[5. 改进的文件API](#5. 改进的文件API)
[八、Unicode 10](#八、Unicode 10)
[九、Remove the JavaEE and CORBA Moudles](#九、Remove the JavaEE and CORBA Moudles)
[十、JEP : 335 : Deprecate the Nashorn JavaScript Engine](#十、JEP : 335 : Deprecate the Nashorn JavaScript Engine)
[十一、JEP : 336 : Deprecate the Pack200 Tools and API](#十一、JEP : 336 : Deprecate the Pack200 Tools and API)
[十五、JEP 331 : Low-Overhead Heap Profiling免费的低耗能飞行记录仪和堆分析仪](#十五、JEP 331 : Low-Overhead Heap Profiling免费的低耗能飞行记录仪和堆分析仪)
**Oracle 表示会对 Java 11 提供大力支持,这一支持将会持续至 2026 年 9 月。这是据 Java 8 以后支持的首个长期版本。**jdk9和jdk10不是,所以接下来介绍的有一些可能是在jdk9或者jdk10就已经支持的。
下面介绍的重点关注以下几个新特性即可:
一、JShell
java9引入了jshell这个交互性工具,让Java也可以像脚本语言一样来运行,可以从控制台启动 jshell ,在 jshell 中直接输入表达式并查看其执行结果。当需要测试一个方法的运行效果,或是快速的对表达式进行求值时,jshell 都非常实用。
把环境变量换成Jdk9,然后打开cmd,查看jdk版本为11,输入jshell就可以开启
尝试使用
除了表达式之外,还可以创建 Java 类和方法。jshell 也有基本的代码完成功能。我们在教人们如何编写 Java 的过程中,不再需要解释 "public static void main(String [] args)" 这句废话。
二、Dynamic Class-File Constants 类文件新添的一种结构
Java的类型文件格式将被拓展,支持一种新的常量池格式:CONSTANT_Dynamic,加载CONSTANT_Dynamic会将创建委托给bootstrap方法。
其目标是降低开发新形式的可实现类文件约束带来的成本和干扰。
三、局部变量类型推断(var "关键字")
java
var javastack = "javastack";
System.out.println(javastack);
局部变量类型推断就是左边的类型直接使用 var 定义,而不用写具体的类型,编译器能根据右边的表达式自动推断类型,如上面的 String 。
java
var javastack = "javastack";
就等于:
java
String javastack = "javastack";
在声明隐式类型的lambda表达式的形参时允许使用var
使用var的好处是在使用lambda表达式时给参数加上注解
java
(@Deprecated var x, @Nullable var y) -> x.process(y);
四、新加的一些实用API
1. 新的本机不可修改集合API
自 Java 9 开始,Jdk 里面为集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它们两个都用来创建不可变的集合,来看下它们的使用和区别。
示例1:
java
var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true
示例2:
java
var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy); // false
示例1和2代码差不多,为什么一个为true,一个为false?
来看下它们的源码:
java
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
return ImmutableCollections.emptyList();
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return new ImmutableCollections.ListN<>(elements);
}
}
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
static <E> List<E> listCopy(Collection<? extends E> coll) {
if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray());
}
}
可以看出 copyOf 方法会先判断来源集合是不是 AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。
示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false.
注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。
除了更短和更好阅读之外,这些方法也可以避免您选择特定的集合实现。在创建后,继续添加元素到这些集合会导致 "UnsupportedOperationException"
2. Stream 加强
Stream 是 Java 8 中的新特性,Java 9 开始对 Stream 增加了以下 4 个新方法。
- 增加单个参数构造方法,可为null
java
Stream.ofNullable(null).count(); // 0
- 增加 takeWhile 和 dropWhile 方法
java
Stream.of(1, 2, 3, 2, 1)
.takeWhile(n -> n < 3)
.collect(Collectors.toList()); // [1, 2]
从第一个元素开始计算,将n<3的元素留下,当 n > 3 时就截止。
java
Stream.of(1, 2, 3, 2, 1)
.dropWhile(n -> n < 3)
.collect(Collectors.toList()); // [3, 2, 1]
这个和上面的相反,一旦 n < 3 不成立就开始计算。
3)iterate重载
这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
3. String 加强
如以下所示。
java
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空白
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 复制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行数统计
"A\nB\nC".lines().count(); // 3
4. Optional 加强
Opthonal 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代的。
java
Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack
5. 改进的文件API
InputStream 终于有了一个非常有用的方法:transferTo,可以用来将数据直接传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例。
java
var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
inputStream.transferTo(outputStream);
}
五、移除的一些其他内容
1、移除项
- 移除了com.sun.awt.AWTUtilities
- 移除了sun.misc.Unsafe.defineClass,
- 使用java.lang.invoke.MethodHandles.Lookup.defineClass来替代
- 移除了Thread.destroy()以及 Thread.stop(Throwable)方法
- 移除了sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault属性
- 移除了jdk.snmp模块
- 移除了javafx,openjdk估计是从java10版本就移除了,oracle jdk10还尚未移除javafx,而java11版本则oracle的jdk版本也移除了javafx
- 移除了Java Mission Control,从JDK中移除之后,需要自己单独下载
- 移除了这些Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM ,AOL and Swisscom
2、废弃项
- -XX+AggressiveOpts选项
- -XX:+UnlockCommercialFeatures
- -XX:+LogCommercialFeatures选项也不再需要
六、标准Java异步HTTP客户端
这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API,该 API 支持同步和异步,而在 Java 11 中已经为正式可用状态,你可以在 java.net 包中找到这个 API。
来看一下 HTTP Client 的用法:
java
public class HTTPClientTest {
@Test
public void testName2() throws Exception {
HttpClient client = HttpClient.newHttpClient(); // 创建Http客户端
// 工厂模式,通过build获得HttpRequest对象
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
// 返回内容的解析器,将返回内容转化为String
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
// 异步请求,非阻塞式
CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request, responseBodyHandler);
sendAsync.thenApply(t -> t.body()).thenAccept(System.out::println);
//HttpResponse<String> response = sendAsync.get();
//String body = response.body();
//System.out.println(body);
}
@Test
public void testName() throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
// 同步请求,阻塞式
HttpResponse<String> response = client.send(request, responseBodyHandler);
String body = response.body();
System.out.println(body);
}
}
上面的 .GET() 可以省略,默认请求方式为 Get!
七、更简化的编译运行程序
JEP 330 : 增强java启动器支持运行单个java源代码文件的程序.
一个命令编译运行源代码,看下面的代码。
java
// 编译
javac Javastack.java
// 运行
java Javastack
在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行,两步执行动作。而在未来的 Java 11 版本中,通过一个 java 命令就直接搞定了,如以下所示。
java
java Javastack.java
注意点 :
- 执行源文件中的第一个类, 第一个类必须包含主方法
- 并且不可以使用别源文件中的自定义类, 本文件中的自定义类是可以使用的.
八、Unicode 10
Unicode 10 增加了8518个字符, 总计达到了136690个字符. 并且增加了4个脚本.同时还有56个新的emoji表情符号
九、Remove the JavaEE and CORBA Moudles
在java11中移除了不太使用的JavaEE模块和CORBA技术
CORBA来自于二十世纪九十年代,Oracle说,现在用CORBA开发现代Java应用程序已经没有意义了,维护CORBA的成本已经超过了保留它带来的好处。
但是删除CORBA将使得那些依赖于JDK提供部分CORBA API的CORBA实现无法运行。目前还没有第三方CORBA版本,也不确定是否会有第三方愿意接手CORBA API的维护工作。
在java11中将java9标记废弃的Java EE及CORBA模块移除掉,具体如下:
1、xml相关的,
java.xml.bind,
java.xml.ws.annotation,
jdk.xml.bind,
jdk.xml.ws被移除,
只剩下java.xml,java.xml.crypto,jdk.xml.dom这几个模块;
2、java.corba,
java.activation,
java.transaction被移除,
但是java11新增一个java.transaction.xa模块
十、 JEP : 335 : Deprecate the Nashorn JavaScript Engine
废除Nashorn javascript引擎,在后续版本准备移除掉,有需要的可以考虑使用GraalVM
十一、JEP : 336 : Deprecate the Pack200 Tools and API
Java5中带了一个压缩工具:Pack200,这个工具能对普通的jar文件进行高效压缩。其 实现原理是根据Java类特有的结构,合并常数 池,去掉无用信息等来实现对java类的高效压缩。由于是专门对Java类进行压缩的,所以对普通文件的压缩和普通压缩软件没有什么两样,但是对于Jar 文件却能轻易达到10-40%的压缩率。这在Java应用部署中很有用,尤其对于移动Java计算,能够大大减小代码下载量。
Java5中还提供了这一技术的API接口,你可以将其嵌入到你的程序中使用。使用的方法很简单,下面的短短几行代码即可以实现jar的压缩和解压:
压缩
java
Packer packer=Pack200.newPacker();
OutputStream output=new BufferedOutputStream(new FileOutputStream(outfile));
packer.pack(new JarFile(jarFile), output);
output.close();
解压
java
Unpacker unpacker=Pack200.newUnpacker();
output=new JarOutputStream(new FileOutputStream(jarFile));
unpacker.unpack(pack200File, output);
output.close();
Pack200的压缩和解压缩速度是比较快的,而且压缩率也是很惊人的,在我是使用 的包4.46MB压缩后成了1.44MB(0.322%),而且随着包的越大压缩率会根据明显,据说如果jar包都是class类可以压缩到1/9的大 小。其实JavaWebStart还有很多功能,例如可以按不同的jar包进行lazy下载和 单独更新,设置可以根据jar中的类变动进行class粒度的下载。
但是在java11中废除了pack200以及unpack200工具以及java.util.jar中的Pack200 API。因为Pack200主要是用来压缩jar包的工具,由于网络下载速度的提升以及java9引入模块化系统之后不再依赖Pack200,因此这个版本将其移除掉。
十二、新的Epsilon垃圾收集器
A NoOp Garbage Collector
JDK上对这个特性的描述是: 开发一个处理内存分配但不实现任何实际内存回收机制的GC, 一旦可用堆内存用完, JVM就会退出.
如果有System.gc()调用, 实际上什么也不会发生(这种场景下和-XX:+DisableExplicitGC效果一样), 因为没有内存回收, 这个实现可能会警告用户尝试强制GC是徒劳.
用法 : -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
java
class Garbage {
int n = (int)(Math.random() * 100);
@Override
public void finalize() {
System.out.println(this + " : " + n + " is dying");
}
}
public class EpsilonTest {
public static void main(String[] args) {
boolean flag = true;
List<Garbage> list = new ArrayList<>();
long count = 0;
while (flag) {
list.add(new Garbage());
if (list.size() == 1000000 && count == 0) {
list.clear();
count++;
}
}
System.out.println("程序结束");
}
}
如果使用选项**-XX:+UseEpsilonGC**, 程序很快就因为堆空间不足而退出
使用这个选项的原因 :
提供完全被动的GC实现, 具有有限的分配限制和尽可能低的延迟开销,但代价是内存占用和内存吞吐量.
众所周知, java实现可广泛选择高度可配置的GC实现. 各种可用的收集器最终满足不同的需求, 即使它们的可配置性使它们的功能相交. 有时更容易维护单独的实现, 而不是在现有GC实现上堆积另一个配置选项.
主要用途如下 :
- 1、性能测试(它可以帮助过滤掉GC引起的性能假象)
- 2、内存压力测试(例如,知道测试用例 应该分配不超过1GB的内存, 我们可以使用-Xmx1g --XX:+UseEpsilonGC, 如果程序有问题, 则程序会崩溃)
非常短的JOB任务(对象这种任务, 接受GC清理堆那都是浪费空间)
1、VM接口测试
2、Last-drop 延迟&吞吐改进
十三、ZGC
ZGC, A Scalable Low-Latency Garbage Collector(Experimental)
ZGC, 这应该是JDK11最为瞩目的特性, 没有之一. 但是后面带了Experimental, 说明这还不建议用到生产环境.
- 1、GC暂停时间不会超过10ms
- 2、既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)
- 3、和G1相比, 应用吞吐能力不会下降超过15%
- 4、为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
- 5、初始只支持64位系统
- 4、为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
- 3、和G1相比, 应用吞吐能力不会下降超过15%
- 2、既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)
ZGC的设计目标是:支持TB级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存),或压缩堆。
GC是java主要优势之一. 然而, 当GC停顿太长, 就会开始影响应用的响应时间.消除或者减少GC停顿时长, java将对更广泛的应用场景是一个更有吸引力的平台. 此外, 现代系统中可用内存不断增长,用户和程序员希望JVM能够以高效的方式充分利用这些内存, 并且无需长时间的GC暂停时间.
ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW, 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长.
用法 :-XX:+UnlockExperimentalVMOptions****-- XX:+UseZGC, 因为ZGC还处于实验阶段, 所以需要通过JVM参数来解锁这个特性
详细可看:新一代垃圾回收器ZGC的探索与实践 - 美团技术团队 (meituan.com)
十四、支持G1上的并行完全垃圾收集
对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。
十五、JEP 331 : Low-Overhead Heap Profiling免费的低耗能飞行记录仪和堆分析仪
通过JVMTI的SampledObjectAlloc回调提供了一个开销低的heap分析方式
- 提供一个低开销的, 为了排错java应用问题, 以及JVM问题的数据收集框架, 希望达到的目标如下 :
- 提供用于生产和消费数据作为事件的API
- 提供缓存机制和二进制数据格式
- 允许事件配置和事件过滤
- 提供OS,JVM和JDK库的事件
- 允许事件配置和事件过滤
- 提供缓存机制和二进制数据格式
- 提供用于生产和消费数据作为事件的API