Java 9 的新特性(主要特性)
JDK 9(Java Development Kit 9)作为Java平台的一个重要更新,引入了一系列的新特性和改进,旨在提高Java应用程序的开发效率、性能、安全性和模块化。以下是JDK 9的主要新特性:
1. 模块化系统(Project Jigsaw)
模块化系统:JDK 9引入了Java平台模块化系统(JPMS),允许开发者将应用程序分解为多个模块,每个模块都定义了自己的依赖关系和公共API。这有助于减少内存开销,提升性能,并简化依赖管理。
模块声明文件:通过
module-info.java
文件来声明模块的名称、依赖、导出的包等。jlink工具:JDK 9新增了
jlink
工具,用于生成自定义的Java运行时映像,只包含应用程序实际需要的模块,从而减少启动时间和内存占用。
例子:假设我们有一个简单的Java项目,该项目包含三个模块:moduleA、moduleB和moduleC。其中,moduleA依赖于moduleB,而moduleB又依赖于moduleC。每个模块都包含一些类和资源,并通过module-info.java文件来定义模块的信息和依赖关系。
目录结构:
MyModularProject/
|-- modules/
| |-- moduleA/
| | |-- src/
| | | |-- main/
| | | | |-- java/
| | | | | |-- com/
| | | | | |-- example/
| | | | | |-- moduleA/
| | | | | |-- ModuleA.java
| | | | |-- resources/
| | |-- module-info.java
| |-- moduleB/
| | |-- src/
| | | |-- main/
| | | | |-- java/
| | | | | |-- com/
| | | | | |-- example/
| | | | | |-- moduleB/
| | | | | |-- ModuleB.java
| | | | |-- resources/
| | |-- module-info.java
| |-- moduleC/
| | |-- src/
| | | |-- main/
| | | | |-- java/
| | | | | |-- com/
| | | | | |-- example/
| | | | | |-- moduleC/
| | | | | |-- ModuleC.java
| | | | |-- resources/
| | |-- module-info.java
|-- application/
| |-- src/
| | |-- main/
| | | |-- java/
| | | | |-- com/
| | | | |-- example/
| | | | |-- Application.java
| |-- module-info.java (可选,取决于是否将application视为一个单独的模块)
|-- build/ (或任何用于存放编译后文件的目录)
|-- bin/ (或任何用于存放可执行文件的目录)
|-- libs/ (可选,用于存放项目依赖的外部库)
|-- docs/ (可选,用于存放项目文档)
|-- .gitignore (或其他版本控制忽略文件)
|-- build.xml (或其他构建脚本,如Maven的pom.xml或Gradle的build.gradle)
|-- README.md (项目说明文件)
1. 模块定义
moduleA
包含一个名为
com.example.moduleA
的包,该包中有一个类ModuleA
。module-info.java
文件定义了模块的依赖关系,即moduleA
需要moduleB
。
// moduleA的module-info.java
module moduleA {
requires moduleB;
exports com.example.moduleA;
}
moduleB
包含一个名为
com.example.moduleB
的包,该包中有一个类ModuleB
。module-info.java
文件定义了模块的依赖关系,即moduleB
需要moduleC
,并导出com.example.moduleB
包。
// moduleB的module-info.java
module moduleB {
requires moduleC;
exports com.example.moduleB;
}
moduleC
包含一个名为
com.example.moduleC
的包,该包中有一个类ModuleC
。module-info.java
文件仅导出com.example.moduleC
包,不依赖其他模块。
// moduleC的module-info.java
module moduleC {
exports com.example.moduleC;
}
2. 模块中的类
每个模块中的类都是简单的Java类,例如:
ModuleA.java
package com.example.moduleA;
public class ModuleA {
public void doSomething() {
System.out.println("Doing something in ModuleA");
}
}
ModuleB.java 和 ModuleC.java 类似,只是包名和类名不同,且可能包含不同的业务逻辑。
3. 使用模块的应用程序
最后,我们创建一个应用程序来使用这些模块。该应用程序将导入moduleA
、moduleB
和moduleC
中的类,并调用它们的方法。
Application.java
import com.example.moduleA.ModuleA;
import com.example.moduleB.ModuleB;
import com.example.moduleC.ModuleC;
public class Application {
public static void main(String[] args) {
ModuleA moduleA = new ModuleA();
ModuleB moduleB = new ModuleB();
ModuleC moduleC = new ModuleC();
moduleA.doSomething();
moduleB.doSomething(); // 假设ModuleB也有doSomething方法
moduleC.doSomething(); // 假设ModuleC也有doSomething方法
}
}
4. 编译和运行
在编译和运行模块化Java应用程序时,需要指定模块路径(--module-path
)和主模块(-m
)。例如:
javac -d mods/moduleA src/moduleA/module-info.java src/moduleA/com/example/moduleA/ModuleA.java
javac -d mods/moduleB src/moduleB/module-info.java src/moduleB/com/example/moduleB/ModuleB.java
javac -d mods/moduleC src/moduleC/module-info.java src/moduleC/com/example/moduleC/ModuleC.java
javac -d mods/application src/application/Application.java
java --module-path mods -m application/com.example.Application
在上述命令中,mods
目录包含编译后的模块,而src
目录包含源代码。请注意,实际编译和运行命令可能因项目结构和开发工具的不同而有所差异。
2. JShell
交互式编程环境:JShell是一个交互式Java REPL(Read-Eval-Print Loop)工具,允许用户直接输入Java代码并立即看到结果,无需编译整个程序。这对于学习和测试新的Java特性非常有用。
3. 集合和Stream API的改进
不可变集合的工厂方法:JDK 9新增了一些不可变集合类的工厂方法,使创建不可变集合变得更加方便。
Stream API的增强:Stream API中添加了新的方法,如
takeWhile
、dropWhile
、ofNullable
以及iterate
方法的重载,提供了更多的灵活性和功能。
例如:
// takeWhile ,从头开始筛选,遇到不满足的就结束
List<Integer> list2 = List.of(1, 2, 3, 4, 3, 0);
List<Integer> listResult2 = list2.stream().takeWhile(x -> x < 3).collect(Collectors.toList());
System.out.println(listResult2); // [1, 2]
// dropWhile ,从头开始删除,遇到不满足的就结束
List<Integer> list2 = List.of(1, 2, 3, 4, 3, 0);
List<Integer> listResult2 = list2.stream().dropWhile(x -> x < 3).collect(Collectors.toList());
System.out.println(listResult2); // [3, 4, 3, 0]
// iterate
IntStream.iterate(0, x -> x < 10, x -> x + 1).forEach(System.out::print); // 0123456789
4. 集合工厂方法
在 Java 9 中为集合的创建增加了静态工厂创建方式,也就是 of 方法,通过静态工厂 of 方法创建的集合是只读集合,里面的对象不可改变。并在不能存在 null 值,对于 set 和 map 集合,也不能存在 key 值重复。这样不仅线程安全,而且消耗的内存也更小。
例如:
// 工厂方法创建集合
List<String> stringList = List.of("a", "b", "c", "d");
Set<String> stringSet = Set.of("a", "b", "c", "d");
Map<String, Integer> stringIntegerMap = Map.of("key1", 1, "key2", 2, "key3", 3);
5. 接口支持定义私有方法
Java 8 引入了默认方法,让接口不再仅限于声明,还能包含具体实现。紧接着,Java 9 进一步增加了私有方法,这一改变显著提升了接口的功能性。此举旨在优化代码结构,因为默认方法虽然解决了接口升级时的兼容性问题,但若多个默认方法共享相同逻辑,则不得不重复编写这些代码。有了私有方法后,接口内部可以复用这些逻辑,避免了代码冗余,使得接口设计更加灵活和高效。
例如:
interface Animal {
void sleep();
default void eat() {
drink();
}
default void doXxx() {
drink();
}
private void drink() {
System.out.println("喝水");
}
}
6. 性能改进
JIT编译器的优化:JDK 9中的JIT(Just-In-Time)编译器得到了优化,提供了更快的编译速度和更高的编译效率。
G1垃圾收集器的改进:G1垃圾收集器在JDK 9中得到了进一步改进,包括并行全GC的引入、内存回收效率的提升以及延迟的降低。
字符串的优化:JDK 9对字符串的内部表示进行了优化,减少了内存占用和处理时间。
删除 JDK 8 中已弃用的垃圾收集器 (GC) 组合
删除了DefNew + CMS、ParNew + SerialOld、增量CMS组合
G1 成为默认垃圾收集器
弃用并发标记扫描 (CMS) 垃圾收集器
弃用并发标记扫描 (CMS) 垃圾收集器。-XX:+UseConcMarkSweepGC使用该选项在命令行上请求时会发出警告消息。Garbage-First (G1) 垃圾收集器旨在替代 CMS 的大多数用途。
7. 其他重要特性
局部变量类型推断(var关键字)(虽然这一特性是在JDK 10中正式引入的,但JDK 9为其奠定了基础):允许开发者在局部变量声明时使用
var
关键字来替代具体的类型,编译器会根据右侧表达式自动推断出变量的类型。HTTP客户端API:JDK 9新增了HTTP客户端API,为开发者提供了更方便的HTTP客户端功能。
多版本兼容JAR:允许在同一个JAR文件中包含不同版本的类,以便在不同版本的Java环境中运行。
评论区