1、JShell
用过Python的同学都知道,Python中的读取-求值-打印循环(Read-Evaluation-Print-Loop)很方便,它的目的在于以即使结果和反馈的形式。
Java9引入JShell这个交互性工具,让Java也可以像脚本语言一样来运行,可以从控制台启动JShell,在JShell中直接输入表达式并查看其执行结果,当需要测试一个方法的运行效果或是快速的对表达式进行求值时,JShell都非常实用。
出了表达式之外,还可以创建Java类和方法,JSell也有基本的代码完成功能,我们在教人们如何编写Java的过程中,不再需要解释“public static void main (String[] args)”这句废话。
2、Dynamic Class-File Constants 类文件新添的一种结构
Java的类型文件格式将被拓展,支持一种新的常量池格式:CONSTANT_Dynamic,加载CONSTANT_Dynamic会将创建委托给BootStrap方法。
目标:降低开发新形式的可实现类文件约束带来的成本和干扰
3、局部变量类型推断(var "关键字")
什么是局部变量类型推断?
var javastack = "javastack";
System.out.println(javastack);
大家看出来了,局部变量类型推断就是左边的类型直接食用var定义,而不用写具体的类型,编译器能根据右边的表达式自动推断类型,如上面的 String 。
var javastack = "javastack";
// ==
String javastack = "javastack";
在声明隐式类型的lambda表达式的形参时允许使用var,使用var的好处是在使用lambda表达式时给参数加上注解如:
(@Nonnull var x, @Nullable var y) -> x.process(y);
如果不加注解直接var用于Lambda表达式,显然是解裤子放屁,所以加上注解才是它主要的用途之一:
Consumer<T> : 消费性函数接口
public void accept(T t);
//直接报错,提示非法的表达式
Consumer<String> consumer = (@Nonnull t) -> System.out.println(t.toUpperCase());
// 完美运行
Consumer<String> consumer = (@Nonnull var t) -> System.out.println(t.toUpperCase());
注意点:
var a; 这样不可以,因为无法推断
类的属性的数据类型不可以使用var
4、新加的一些实用API
4.1、集合中新API介绍
自Java9开始,JDK里面为集合(List/Set/Map)都添加了of和copyOf方法,它们两个都用来创建不可变的集合,来看一下它们的使用和区别:
// 老方法
@Test
public void test1() {
List<Stirng> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
}
// 新方法
@Test
public void test2() {
//使用新的API则更简单
List<Stirng> list = List.of("aa","bb","cc","dd");
//但是不可以使用追加
list.add("ee") // 会报错,底层直接抛出异常
}
4.2、流中新的API介绍
Stream是Java8种的新特性,Java9开始对Stream增加了以下4个新方法:
/**
* 流的处理
* 1、创建流
* 2、中间操作
* 3、终止操作 - 打印在此操作
*/
@Test
public void test1() {
Stream<Integer> stream1 = Stream.of(3 ,9 ,20 ,22 ,40);
// stream1.forEach(t -> System.out.println(t));
stream1.forEach(System.out::println);
//流中没有数据
Stream<Object> stream2 = Stream.of();
stream2.forEach(System.out::println);
//流中传入Null值来创建流对象
Stream<Object> stream3 = Stream.ofNullable(null);
stream3.forEach(System.out::println)
}
@Test
public void test2() {
// 新方法 takeWhile,dropWhile
// 从流中一直获取判定器为真的元素,一旦遇到元素为假,就终止处理。
Stream<Integer> stream1 = Stream.of(3 ,9 ,20 ,22 ,40);
Stream<Integer> stream2 = stream1.takeWhile(t -> t % 2 != 0);
stream1.forEach(System.out::println); // 输出:3 ,9
Stream<Integer> stream2 = stream1.dropWhile(t -> t % 2 != 0);
stream1.forEach(System.out::println); // 输出:20 ,22 ,40
}
@Test
public void test2() {
// 流的迭代,创建流
//老方法,设置迭代到第十次就结束
Stream<Integer> stream1 = Stream.iterate(1 , t -> (2 * t) + 1);
stream1.limit(10).forEach(System.out::println);
//新方法。设置有限的迭代,值在1000以内则打印
Stream<Integer> stream2 = Stream.iterate(1 ,t -> t < 1000 ,t -> (2 * t) + 1);
stream1.limit(10).forEach(System.out::println);
}
4.3、字符串中新的API介绍
如以下所示:
// 判断字符串是否为空
"".isBlank(); // true
//去除首尾空白
" bigbey ".strip(); // "bigbey"
//去除尾部空白
"bigbey ".stripTrailing(); // "bigbey"
//去除首部空白
" bigbey".stripLeading(); // "bigbey"
//复制字符串
"bigbey".repeat(3); "bigbeybigbeybigbey"
//行数统计
"A\nB\nC\n".lines().count(); // 3
4.4、Optional加强
Optional也增加了几个非常酷的方法,现在可以很方便的将一个Optional转换成一个Stream或者当一个空Optional时给它一个替代的。
// of方法中如果传入的参数是null。会抛出空指针异常
// Optional<String> optional = Optional.of(null);
// ofNullable可以兼容空指针,但是实际传入null后要小心
Optional<Object> optional = Optional.ofNullable(null);
Object object1 = optional.orElse("abc"); // 如果内部引用为空,则返回参数中的引用,否则返回内部引用
System.out.println(object1);
Object object2 = optional.orElseThrow();
System.out.println(object2); // 抛出NoSuchElementException: No value present
4.5、改进的文件API
InputStream加强
InputStream终于有了一个非常有用的方法:transferTo,可以用来将数据直接传输到OutputStream,这是在处理原始数据流时非常常见的一种用法,如下所示:
@Test
public void testName() throws Exception {
var cl = this.getClass().getClassaLoader();
var is = cl.getResourceAsStream("file1");
try (var or = new FileOutputStream("file2")) {
is.transferTo(os); // 把输入流中的所有数据直接自动复制到输出流中
}
is.close();
}
5、标准Java异步HTTP客户端
这是Java9开始引入的一个处理HTTP请求的HTTP Client API,该API支持同步和异步,而在Java11中已经为正式可用状态,你可以在java.net包中找到这个API。
@Test
public void testName1() 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);
}
@Test
public void testName2() 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();
CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request, responseBodyHandler);
HttpResponse<String> response = sedAsync.get();
String body = response.body();
System.out.println(body);
}
6、移除的一些其他内容
移除项:
移除了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
废弃项:
-XX+AggressiveOpts选项
-XX:+UnlockCommercialFeatures
-XX:+LogCommercialFeatures选项也不再需要
7、更简化的编译运行程序
JEP 330 : 增强Java启动器支持运行单个Java源代码的程序。
注意点:
执行源文件中的第一个类,第一个类必须包含主方法
不可以使用别的源文件中的自定义类,本文件中的自定义类是可以使用的
在我们的认知里,要运行一个Java源代码必须先编译,然后运行,两步执行动作,则会生成一个class文件,而在Java11中,则通过一个Java命令就直接搞定了,并不会生成class文件
# 编译
javac bigbey.java
#运行
java bigbey
# 改进后
java bigbey.java
8、Unicode 10
Unicode 10 增加了8518个字符,总计达到了136690个字符,并且增加了4个脚本,同时还有56个新的emoji表情符号。
9、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.ws 被移除,
java.xml.bind 被移除,
java.xml.ws 被移除,
java.xml.ws.annotation 被移除,
jdk.xml.bind 被移除,
jdk.xml.ws被移除,
只剩下java.xml,java.xml.crypto,jdk.xml.dom这几个模块;
(2)java.corba,
java.se.ee 被移除,
java.activation 被移除,
java.transaction 被移除,
但是java11新增一个java.transaction.xa模块
10、JEP:335 Deprecate the Nashorn JavaScript Engine
废除Nashorn javascript引擎,在后续版本准备移除掉,有需要的可以考虑使用GraalVM。
11、JEP:336 Deprecate the Pack200 Tools and API
Java5中的一个压缩工具:pack200,这个工具能够压缩jar包,其主要作用就是解决客户端之间传输太大文件慢而出现的一种技术,但是随着现在5G网络的诞生,这个工具则不在好用,而且配置起来也很麻烦所以弃用。
12、Epsilon垃圾收集器
A NoOp Garbage Collector
JDK上对这个特性的描述是: 开发一个处理内存分配但不实现任何实际内存回收机制的GC, 一旦可用堆内存用完, JVM就会退出.
如果有System.gc()调用, 实际上什么也不会发生(这种场景下和-XX:+DisableExplicitGC效果一样), 因为没有内存回收, 这个实现可能会警告用户尝试强制GC是徒劳.
用法 : -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
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实现上堆积另一个配置选项.
主要用途如下 :
性能测试(它可以帮助过滤掉GC引起的性能假象)
内存压力测试(例如,知道测试用例 应该分配不超过1GB的内存, 我们可以使用-Xmx1g –XX:+UseEpsilonGC, 如果程序有问题, 则程序会崩溃)
非常短的JOB任务(对象这种任务, 接受GC清理堆那都是浪费空间)
VM接口测试 Last-drop 延迟&吞吐改进
13、ZGC垃圾收集器
这应该是JDK11最为瞩目的特性, 没有之一. 但是后面带了Experimental, 说明这还不建议用到生产环境.
ZGC, A Scalable Low-Latency Garbage Collector(Experimental)
ZGC, 这应该是JDK11最为瞩目的特性, 没有之一. 但是后面带了Experimental, 说明这还不建议用到生产环境.
GC暂停时间不会超过10ms
既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)
和G1相比, 应用吞吐能力不会下降超过15%
为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
初始只支持64位系统
ZGC的设计目标是:支持TB级内存容量,暂停时间低(小于10ms),对整个程序吞吐量的影响小于15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存),或压缩堆。
GC是java主要优势之一. 然而, 当GC停顿太长, 就会开始影响应用的响应时间.消除或者减少GC停顿时长, java将对更广泛的应用场景是一个更有吸引力的平台. 此外, 现代系统中可用内存不断增长,用户和程序员希望JVM能够以高效的方式充分利用这些内存, 并且无需长时间的GC暂停时间.
ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW, 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长.
用法 : -XX:+UnlockExperimentalVMOptions –XX:+UseZGC, 因为ZGC还处于实验阶段, 所以需要通过JVM参数来解锁这个特性,只支持Linux系统。
14、完全支持Linux容器(包括Docker)
许多运行在Java虚拟机中的应用程序(包括Apache Spark和Kafka等数据服务以及传统的企业应用程序)都可以在Docker容器中运行。但是在Docker容器中运行Java应用程序一直存在一个问题,那就是在容器中运行JVM程序在设置内存大小和CPU使用率后,会导致应用程序的性能下降。这是因为Java应用程序没有意识到它正在容器中运行。随着Java 10的发布,这个问题总算得以解决,JVM现在可以识别由容器控制组(cgroups)设置的约束。可以在容器中使用内存和CPU约束来直接管理Java应用程序,其中包括:
遵守容器中设置的内存限制
在容器中设置可用的CPU
在容器中设置CPU约束
15、支持G1上的并行完全垃圾收集。
对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。
16、JEP 331 : Low-Overhead Heap Profiling免费的低耗能飞行记录仪和堆分析仪。
通过JVMTI的SampledObjectAlloc回调提供了一个开销低的heap分析方式
提供一个低开销的, 为了排错java应用问题, 以及JVM问题的数据收集框架, 希望达到的目标如下 :
提供用于生产和消费数据作为事件的API
提供缓存机制和二进制数据格式
允许事件配置和事件过滤
提供OS,JVM和JDK库的事件
17、JEP 329 : 实现RFC7539中指定的ChaCha20和Poly1305两种加密算法, 代替RC4
实现 RFC 7539的ChaCha20 and ChaCha20-Poly1305加密算法
RFC7748定义的秘钥协商方案更高效, 更安全. JDK增加两个新的接口
XECPublicKey 和 XECPrivateKey
KeyPairGenerator kpg = KeyPairGenerator.getInstance(“XDH”);
NamedParameterSpec paramSpec = new NamedParameterSpec(“X25519”);
kpg.initialize(paramSpec);
KeyPair kp = kgp.generateKeyPair();
KeyFactory kf = KeyFactory.getInstance(“XDH”);
BigInteger u = new BigInteger(“xxx”);
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);
KeyAgreement ka = KeyAgreement.getInstance(“XDH”);
ka.init(kp.getPrivate());
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();
18、新的默认根权限证书集。
19、最新的HTTPS安全协议TLS 1.3。
实现TLS协议1.3版本, TLS允许客户端和服务器端通过互联网以一种防止窃听, 篡改以及消息伪造的方式进行通信.
20、Java Flight Recorder
Flight Recorder源自飞机的黑盒子
Flight Recorder以前是商业版的特性,在java11当中开源出来,它可以导出事件到文件中,之后可以用Java Mission Control来分析。可以在应用启动时配置java -XX:StartFlightRecording,或者在应用启动之后,使用jcmd来录制,比如
$ jcmd JFR.start
$ jcmd JFR.dump filename=recording.jfr
$ jcmd JFR.stop
是 Oracle 刚刚开源的强大特性。我们知道在生产系统进行不同角度的 Profiling,有各种工具、框架,但是能力范围、可靠性、开销等,大都差强人意,要么能力不全面,要么开销太大,甚至不可靠可能导致 Java 应用进程宕机。
而 JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR,用以在复杂环境中进行“After-the-fact”分析。还需要苦恼重现随机问题吗?JFR 让问题简化了很多。
在保证低开销的基础上,JFR 提供的能力也令人眼前一亮,例如:我们无需 BCI 就可以进行 Object Allocation Profiling,终于不用担心 BTrace 之类把进程搞挂了。对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java、C++ 等扩展 API,可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。
评论区