post:加入Java 9新特性的文章。
This commit is contained in:
parent
a9e4fe8400
commit
a2d964271b
|
@ -22,6 +22,7 @@ date: 2021-05-20 15:06:57
|
|||
本系列的文章有:
|
||||
|
||||
- {% post_link nf-java8 %}
|
||||
- {% post_link nf-java9 %}
|
||||
|
||||
## Lambda表达式
|
||||
|
||||
|
|
118
source/_posts/nf-java9.md
Normal file
118
source/_posts/nf-java9.md
Normal file
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
title: Java 9的新特性
|
||||
tags:
|
||||
- JVM
|
||||
- Java
|
||||
- Optional
|
||||
- JPMS
|
||||
- 新特性
|
||||
categories:
|
||||
- - JVM
|
||||
- Java
|
||||
keywords: ''
|
||||
date: 2021-05-20 15:15:29
|
||||
---
|
||||
|
||||
Java 9在Java 8的基础上做了许多重大的改进,尤其是引入了模块系统,这直接导致使用Java 8的程序在Java 9中可能无法通过编译。除此之外,Java 9还对Java 8中引入的功能做了一些增补和改进。<!-- more -->
|
||||
|
||||
本系列的文章有:
|
||||
|
||||
- {% post_link nf-java8 %}
|
||||
- {% post_link nf-java9 %}
|
||||
|
||||
## Optional
|
||||
|
||||
Java 9为Optional类增加了以下三个方法。
|
||||
|
||||
* `stream()`,将一个Optional转换为一个Stream,如果Optional为空,则Stream将不包含任何值。
|
||||
* `ifPresentOrElse(Consumer<T>, Runnable)`,如果Optional包含值,就用其中的值调用Consumer函数,否则就启动一个任务。
|
||||
* `or(Supplier<Optional<T>>)`,如果值存在就返回Optional中的值,否则返回预设值。
|
||||
|
||||
## Stream
|
||||
|
||||
Stream类现在也增加了一些更加便利的方法。
|
||||
|
||||
* `takeWhile(Predicate<T>)`,从流中返回尽可能多的元素,直到Predicate返回`false`为止。
|
||||
* `dropWhile(Predicate<T>)`,从流中丢弃尽可能多的元素,直到Predicate返回`false`为止。
|
||||
* `iterate(T, Predicate<T>, UnaryOperator<T>)`,允许使用初始种子使用`UnaryOperator`函数创建无限流,直到`Predicate`返回`false`为止。
|
||||
* `ofNullable(T)`,用可空对象创建一个只有单个元素的流,可以通过检查流来预防NullPointException。
|
||||
|
||||
## 私有接口方法
|
||||
|
||||
Java 8引入默认方法之后,在接口中可以定义常量、抽象方法、默认方法和静态方法。Java 9在这个基础上引入了私有方法,从而为接口增加了私有方法和私有静态方法。接口中的私有方法和私有静态方法使用`private`关键字修饰。`private`关键字在接口中不能用来修饰抽象方法。
|
||||
|
||||
接口中的私有方法仅能够提供接口本身使用,不能通过接口访问或者通过继承从另一个接口或者类来访问。
|
||||
|
||||
## 资源操作
|
||||
|
||||
资源操作(try-with-resources)是Java 7中引入的新的异常处理机制。这里的资源是指在被程序使用后,必须要被关闭的对象。资源操作确保了每个被使用的资源都能够在语句块结束时关闭。所有实现了`java.lang.AutoCloseable`接口(包括`java.io.Closeable`接口)的对象都可以作为资源使用。
|
||||
|
||||
在Java 7语法规则中,资源变量必须在资源操作语句中声明,例如以下示例。
|
||||
|
||||
```java
|
||||
String readData(String message) throws IOException {
|
||||
Reader input = new StringReader(message);
|
||||
BufferedReader reader = new BufferReader(input);
|
||||
// 这里需要重新声明一个变量,不能直接使用外部作用域定义的变量
|
||||
try (BufferedReader reader1 = reader) {
|
||||
return reader1.readLine();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在Java 9 中如果这个资源是final的或者等效于final,那么就无需重新声明一个变量而直接使用了,所以以上示例可以改写为以下形式。
|
||||
|
||||
```java
|
||||
String readData(String message) throws IOException {
|
||||
Reader input = new StringReader(message);
|
||||
BufferedReader reader = new BufferReader(input);
|
||||
// 这里无需重新声明一个变量
|
||||
try (reader) {
|
||||
return reader.readLine();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> final变量表示常量,只能被赋值一次,其值不可再更改。所以只做读取使用和无其他副作用的局部变量会被作为final变量优化处理。
|
||||
|
||||
## 模块系统
|
||||
|
||||
模块系统是Java 9所做的最大改变,模块是代码和数据的封装,其中代码被组织为多个包,数据则包含资源文件和其他静态信息。Java 9编译得到的最终Artifact可以是Jar文件,也可以是模块系统引入的新增的JMOD文件。
|
||||
|
||||
模块的根目录中需要放置一个`module-info.java`文件来描述模块,该文件在编译后位于模块Artifact的根目录中。在这个文件中可以使用关键字`module`声明一个模块,例如以下示例。
|
||||
|
||||
```java
|
||||
module xyz.archgrid.samplemodule {
|
||||
requires java.base; // 其实这一条引用是不必书写的,这里只是做一个示例
|
||||
}
|
||||
```
|
||||
|
||||
模块中的其他代码与之前版本Java的代码组织形式相同。但是在编译时又不同了,需要使用`javac -d 模块输出目录`。而执行一个模块则需要使用命令`java --module-path 模块所在目录 -m 模块名/报名.主类名`。
|
||||
|
||||
传统Java程序打包后是使用`--class-path`(简写为`-cp`)来指定Jar包所在位置的。例如`java --class-path sample.jar some.package.MainClass`。运行模块则是用`--module-path`(简写为`-p`)来指定模块的位置。
|
||||
|
||||
模块的出现使得构建和维护一个大型库或者应用变得更加容易,并且提升了Java的性能,使得应用不需要使用大段的CLASS-PATH来引用过量的依赖。
|
||||
|
||||
模块描述中可以使用以下关键字来控制其他应用对包内内容的访问。
|
||||
|
||||
* `exports`,选择需要导出的类。
|
||||
* `requires`,引用其他的模块。需要注意的是,`java.base`会被默认加入引用,不需要显式书写。每个模块仅会被引入一次,并且只能访问已经导出的类。
|
||||
|
||||
被依赖模块可以通过命令`jar --create --file 目标jar文件 -C 已编译目录 要打包内容`来完成打包。依赖其他模块的模块可以通过命令`javac -p 依赖模块目录 -d 输出目录 源文件集`来完成编译,并使用命令`jar --create -f 目标jar文件 -p 依赖模块目录 --main-class 主类 -C 已编译目录 要打包内容`。在运行最终的模块时需要指定所有模块的位置,例如`java -p 主模块:依赖模块 -m 主类`。
|
||||
|
||||
## 兼容Jar包
|
||||
|
||||
兼容Jar包可以允许创建针对不同的Java环境选择不同class版本的Jar包。要创建兼容Jar包,需要在`MANIFEST.MF`文件中使用增加的属性:`Multi-Release: true`。此外还需要在`META-INF`目录中增加一个名为`versions`目录用于存放针对不同版本JRE的class文件。
|
||||
|
||||
编译用于不同版本JRE的class文件,可以使用`javac --release n`命令,其中参数`n`为目标版本号,例如7、8、9等。打包Jar时可以使用命令`jar -c -f 输出文件 -C 源目录 . --release 额外版本号 -C 额外版本源目录 .`。
|
||||
|
||||
## 其他新特性
|
||||
|
||||
Java 9中还有一些新特性比较简单,属于语法功能的增补。
|
||||
|
||||
* 匿名类中可以使用钻石操作符`<>`了。
|
||||
* 集合工厂增加了`of()`、`ofEntries()`等可接受更多参数的重载方法来快速创建集合。
|
||||
* 增加了`ProcessHandle`接口来增强对本地进程的支持,允许查询进程状态并管理进程。
|
||||
* 除原有的`@Deprecated`注解上增加了字符串型参数`since`来标注API被弃用的版本,布尔型参数`forRemoval`来标注API将在未来被删除。
|
||||
* 将Java 8中引入的`CompletableFuture<T>`类进行了扩展,增加了延迟和超时等功能,并添加了新的工厂方法。
|
||||
|
Loading…
Reference in New Issue
Block a user