Java学习笔记17-Java9&10&11新特征
一、Java 9新特性
Java 9的新特性官方文档
从Java 9发布开始,Java的计划发布周期变为6个月。
总的来说,Java 9的新特性主要有:
- 模块化系统
- jShell命令
- 多版本兼容jar包
- 接口的私有方法
- 钻石操作符的使用升级
- 语法改进:try语句
- String存储结构变更
- 便利的集合特性:of()
- 增强的StreamAPI
- 全新的HTTP客户端API
- Deprecated的相关API
- javadoc的HTML5支持
- Javascript引擎升级:Nashorn
- java的动态编译器
1、JDK和JRE目录结构改变
Java 9开始,JDK的目录结构发生改变。
Java 9之前的JDK目录:
Java 9及以后的JDK目录结构:
2、模块化系统
Java 9之前的项目,存在的缺陷:
- Java运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)
- 当代码库越来越大,创建复杂,代码交错的几率呈指数级的增长。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了Java开发和运行效率的提升。
- 很难真正地对代码进行封装,而系统并没有对不同部分(也就是JAR文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的API。
Java 9提出Jigsaw(积木,拼图)项目的概念,之后的版本改名为Modularity,表示模块化项目。
本质上来说,模块(module)的概念其实就是package外再裹一层,就是用模块来管理各个package,通过声明某个package暴露,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
模块化的实现目标:
- 模块化的主要目的在于减少内存的开销
- 只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护
- 改进Java SE平台,使其可以适应不同大小的计算设备
- 改进其安全性,可维护性,提高性能
模块化的使用
模块将由通常的类和新的模块声明文件(module-info.java
)组成。该文件位于java代码结构的顶层,描述符明确地定义了模块需要什么依赖关系,以及哪些模块被外部使用。在exports
子句中未提及的所有包默认情况下将封装在模块中,不能在外部使用。
如图:
要想在java9demo
模块中调用java9test
模块下包中的结构,需要在java9test
的module-info.java
中声明:
1 |
|
对应地,需要在java9demo
模块的src下,创建module-info.java
文件,声明下面语句:
1 |
|
3、jShell命令
交互式编程环境REPL(read-evaluate-print-loop)指的是以交互式的方式对语句和表达式求值。
jShell是Java语言在Java 9新增的REPL工具,让Java像脚本语言一样运行。无需创建Java文件就可以运行程序。
jShell也可以从文件中加载语句或者将语句保存到文件中。
jShell也可以使用tab键进行自动补全和自动添加分号。
使用方法
启动:在命令提示符窗口中输入jshell
(Windows的DOS命令不区分大小写)即可打开jShell
使用:
/help intro
:获取帮助/list
:控制正在执行的操作/help
:获取有关命令的列表/exit
:退出jShell
jShell环境下,语句末尾的
;
可以省略,为了提高代码可读性,建议不要省略。jShell中没有受检异常(编译时异常)
4、语法改进:接口的私有方法
Java 8中对于接口添加了静态方法和默认方法,Java 9中加入了私有方法。接口更像一个抽象类了。
5、语法改进:钻石操作符使用升级
钻石操作符(diamond operator):<>
Java 9中钻石操作符可以和匿名实现类共同使用:
1 |
|
6、语法改进:try语句
Java 8中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过:
1 |
|
Java9中,用资源语句编写try将更容易,可以在try子句中使用已经初始化过的资源,但是此时的资源是final
的,无法再被修改:
1 |
|
7、String存储结构改变
Java 9开始,String(包括StringBuffer、StringBuilder)的底层存储结构不再是char型数组,而是用byte数组加编码标记,节省空间。
8、集合工厂方法
Java 9之前,如果想创建一个只读、不可改变的集合,需要好几步:
1 |
|
Java 9为集合类添加了静态方法of()
,用于构建只读集合。包括List
、Set
、Map
。只读集合如果添加元素,会导致UnsupportedOperationException
异常。
List中的of()
方法
Map中的of()
方法
9、InputStream加强
InputStream添加transferTo
方法,可以用来将数据直接传输到OutputStream
,这是在处理原始数据流时非常常见的一种用法:
1 |
|
10、增强的Stream API
Java 9中,Stream接口中添加了4个新的方法:
default Stream<T> takeWhile(Predicate<? super T> predicate)
:返回从开头开始,按照指定规则的尽量多的元素(一旦遇到不符合条件的数据,就停止)。default Stream<T> dropWhile(Predicate<? super T> predicate)
:返回符合条件的前n个元素之后的元素,与takeWhile
互补。public static<T> Stream<T> ofNullable(T t)
:创建一个单元素的Stream
实例,t
可以为空(Java 8中的of()
方法不能为单个null
)public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
:iterate
的重载方法,可以提供一个Predicate
(判断条件)来指定什么时候结束迭代。
11、Optional创建Stream对象
除了对Stream
本身的扩展,Optional
和Stream
之间的结合也得到了改进。
现在可以通过Optional
的新方法stream()
将一个Optional
对象转换为一个(可能是空的) Stream
对象。
比如:
1 |
|
12、JavaScript引擎升级
Nashorn项目在Java 9中得到改进。
二、Java 10新特性
Java 10共定义了109个新特性,其中包含12个JEP(JDK Enhancement Proposal),还有新API和JVM规范以及Java语言规范上的改动。
12个JEP:
- 286:Local-Variable Type Inference:局部变量类型推断
- 296:Consolidate the JDK Forest into a Single Repository:JDK库的合并
- 304:Garbage-Collector Interface:统一的垃圾回收接口
- 307:Parallel Full GC for G1:为G1提供并行的Full GC
- 310:Application Class-Data Sharing:应用程序类数据(AppCDS)共享
- 312:Thread-Local Handshakes ThreadLocal:握手交互
- 313:Remove the Native-Header Generation Tool (javah):移除JDK中附带的javah工具
- 314:Additional Unicode Language-Tag Extensions:使用附加的Unicode语言标记扩展
- 316:Heap Allocation on Alternative Memory Devices:能将堆内存占用分配给用户指定的备用内存设备
- 317:Experimental Java-Based JIT Compiler:使用基于Java的JIT编译器
- 319:Root Certificates:根证书
- 322:Time-Based Release Versioning:基于时间的发布版本
其中值得关注的是:Local-Variable Type Inference,局部变量类型推断。
1、局部变量类型推断
使用var
代替局部变量的显示类型声明,适用于编译器可以推断出类型的地方,包括以下三种情况:
- 局部变量的初始化
- 增强for循环中的索引
- 传统for循环中的索引
代码实现:
1 |
|
var
不适用于以下情况:
- 没有初始化的局部变量声明
- 方法的返回类型
- 方法的参数类型
- 构造器的参数类型
- 属性
- catch块
原理:在处理var
时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中。正确使用var
生成的字节码文件和不使用var
时生成的字节码文件内容是相同的。
注意:
var
不是一个关键字。因此可以作为方法名或变量名,但是不能用它作为类名。除了不能用作类名以外,别的都可以。var
并不会改变Java是一门静态类型语言的事实。这一特征只发生在编译阶段,对运行时性能不会产生任何影响。编译器在编译阶段自动推断出类型,然后写入字节码文件。反编译出的字节码文件仍是传统带类型的代码。
2、集合新增创建不可变集合的方法
Java 9 为集合(List
,Set
,Map
)添加了of()
方法用于创建不可变集合,Java 10 则添加了copyOf()
方法,同样用于创建不可变集合,二者的区别如下:
1 |
|
上面两种结果不同,是因为copyOf()
会先判断参数集合是不是AbstractImmutableList
(不可变)类型的,如果是,则直接返回,否则会调用of
方法创建一个只读集合并返回。
三、Java 11新特性
1、概述
Java 11是一个长期支持版本,包括ZGC、Http Client等重要更新,以及17个值得关注的JEP。
2、新增字符串处理方法
Java 11新增了一系列字符串处理的方法:
方法 | 描述 |
---|---|
boolean isBlank() |
判断字符串是否为空白 |
String strip() |
去除首尾空白 |
String stripTrailing() |
去除尾部空格 |
String stripLeading() |
去除首部空格 |
String repeat(int n) |
复制字符串n次 |
Stream<String> lines() |
统计行数 |
strip
和trim
的区别是:trim
无法消除Unicode空白字符\u2000
,而strip
可以。
3、Optional加强
Optional增加了几个方法,Java 9-11新增的方法:
新增方法 | 描述 | 新增的版本 |
---|---|---|
booleanisEmpty() |
判断value 是否为空 |
JDK 11 |
ifPresentOrElse(Consumer<superT> action, Runnable emptyAction) |
value 非空,执行参数1功能;如果value 为空,执行参数2功能 |
JDK 9 |
Optional<T> or (Supplier<?extends Optional<?extendsT>>supplier) |
value 非空,返回对应的Optional ;value 为空,返回形参封装的Optional |
JDK 9 |
Stream<T>stream() |
value 非空,返回仅包含此value 的Stream ;否则,返回一个空的Stream |
JDK 9 |
TorElseThrow() |
value 非空,返回value ;否则抛异常NoSuchElementException |
JDK 10 |
4、局部变量类型推断升级
新增了在var
上添加注解的语法格式:
1 |
|
5、全新的HTTP客户端API
Java9开始引入的处理HTTP请求的HTTPClient API,该API支持同步和异步,在Java11中已经为正式可用状态,可以在java.net
包中找到这个API。
它将替代仅适用于blocking模式的HttpURLConnection
(HttpURLConnection
是在HTTP1.0的时代创建的,并使用了协议无关的方法),并提供对WebSocket和HTTP/2的支持。
代码实现:
1 |
|
6、更简化的编译运行程序
传统的编译运行过程:
①编译:javac hello.java
,生成字节码文件hello.class
②运行:java hello
,运行字节码文件
Java 11中简化了编译运行过程,以上两步可以使用java hello.java
一步代替。
使用简化命令的要求:
- 执行源文件的第一个类,第一个类必须包含主方法。
- 不可以使用其他源文件中的自定义类,可以使用本文件中的自定义类。
7、废弃Nashorn引擎
Java 11废弃了Nashorn引擎,可以考虑使用GraalVM
8、ZGC
GC是Java的主要优势之一。GC停顿太长,会影响应用的响应时间,消除或者减少GC停顿时长,java将对更广泛的应用场景是一个更有吸引力的平台。随着现代系统可用内存不断增长,用户希望JVM能够以高效的方式利用这些内存,并且无需长时间的GC暂停时间。
ZGC(A ScalableLow-Latency Garbage Collector(Experimental) ),是JDK11最为瞩目的特性。
ZGC是一个并发,基于region,压缩型的垃圾收集器,只有root扫描阶段会STW(stop the world),因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。
ZGC优势:
- GC暂停时间不会超过10ms。
- 既能处理几百兆的小堆,也能处理几个T的大堆(OMG)。
- 和G1相比,应用吞吐能力不会下降超过15%。
- 为未来的GC功能和利用colord指针以及Load barriers优化奠定基础。
- 初始只支持64位系统。
ZGC的设计目标是:支持TB级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于15%。将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存),或压缩堆。
9、其他新特性
Java 11的其他新特征:
- Unicode10
- Deprecate the Pack200 Tools and API
- 新的Epsilon垃圾收集器
- 完全支持Linux容器(包括Docker)
- 支持G1上的并行完全垃圾收集
- 最新的HTTPS安全协议TLS1.3
- Java Flight Recorder
四、总结展望
1、标准化和轻量级的JSON API
一个标准化和轻量级的JSON API被许多Java开发人员所青睐。但是由于资金问题无法在Java当前版本中见到,但并不会削减掉。Java平台首席架构师Mark Reinhold在JDK9邮件列中说:“这个JEP将是平台上的一个有用的补充,但是在计划中,它并不像Oracle资助的其他功能那么重要,可能会重新考虑JDK10或更高版本中实现。”
2、新的货币API
对许多应用而言货币价值都是一个关键的特性,但JDK对此却几乎没有任何支持。严格来讲,现有的java.util.Currency
类只是代表了当前ISO4217货币的一个数据结构,但并没有关联的值或者自定义货币。
JDK对货币的运算及转换也没有内建的支持,更别说有一个能够代表货币值的标准类型了。
如果用Maven的话,可以做如下的添加,即可使用相关的API处理货币:
1 |
|
3、展望
- 随着云计算和AI等技术浪潮,当前的计算模式和场景正在发生翻天覆地的变化,不仅对Java的发展速度提出了更高要求,也深刻影响着Java技术的发展方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微服务甚至是函数(FaaS,Function-as-a-Service)所替代。
- Java虽然标榜面向对象编程,却毫不顾忌的加入面向接口编程思想,又扯出匿名对象之概念,每增加一个新的东西,对Java的根本所在的面向对象思想的一次冲击。反观Python,抓住面向对象的本质,又能在函数编程思想方面游刃有余。Java对标C/C++,以抛掉内存管理为卖点,却又陷入了JVM优化的噩梦。选择比努力更重要,选择Java的人更需要对它有更清晰的认识。
- Java需要在新的计算场景下,改进开发效率。这话说的有点笼统,我谈一些自己的体会,Java代码虽然进行了一些类型推断等改进,更易用的集合API等,但仍然给开发者留下了过于刻板、形式主义的印象,这是一个长期的改进方向。
五、Reference
Java笔记系列,参考自尚硅谷Java核心教程,衷心感谢。
- 本文作者:Kangshitao
- 本文链接:http://kangshitao.github.io/2021/04/19/java-note-1701/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!