Java 9 核心特性解析
Java 9在2017年9月发布,带来了模块系统等重大变革,是Java平台现代化的重要一步。
模块系统 (Project Jigsaw)
特性概述
模块系统是Java 9最重要的特性,旨在解决Java平台和应用程序的可伸缩性问题,提供更好的封装性和依赖管理。
技术细节
模块是一个自描述的Java代码和数据的集合,通过module-info.java
文件定义:
// module-info.java
module com.example.myapp {
// 导出包,使其对其他模块可见
exports com.example.myapp.api;
// 声明对其他模块的依赖
requires java.base; // 隐式依赖,可省略
requires java.sql;
// 允许反射访问
opens com.example.myapp.internal to com.example.framework;
// 提供服务实现
provides com.example.service.MyService with com.example.myapp.impl.MyServiceImpl;
// 使用服务
uses com.example.service.OtherService;
}
模块系统的主要概念:
- 强封装:默认情况下,模块中的包对其他模块不可见
- 显式依赖:模块必须声明其依赖关系
- 可靠配置:编译时和运行时都会验证模块依赖
- 模块化JDK:JDK本身被分解为约100个模块
应用场景
- 大型应用模块化
// 应用API模块
module app.api {
exports com.app.api;
}
// 应用实现模块
module app.impl {
requires app.api;
requires database.api;
provides com.app.api.UserService with com.app.impl.UserServiceImpl;
}
// 数据库API模块
module database.api {
exports com.db.api;
}
// 数据库实现模块
module database.impl {
requires database.api;
provides com.db.api.Repository with com.db.impl.JdbcRepository;
}
- 创建自定义运行时镜像
# 使用jlink创建包含所需模块的自定义运行时
jlink --module-path $JAVA_HOME/jmods:mods --add-modules app.main --output appruntime
- 服务加载
// 使用ServiceLoader加载服务实现
ServiceLoader<MyService> services = ServiceLoader.load(MyService.class);
for (MyService service : services) {
service.doSomething();
}
JShell - 交互式Java REPL
特性概述
JShell是Java 9引入的交互式编程环境,允许开发者快速测试Java代码片段,无需编写完整的类或方法。
技术细节
JShell支持以下功能:
- 执行表达式、语句和声明
- 自动导入常用包
- 代码补全和语法高亮
- 访问执行历史
- 保存和加载会话
# 启动JShell
$ jshell
# 执行简单表达式
jshell> 2 + 2
$1 ==> 4
# 定义变量
jshell> String greeting = "Hello, World!"
greeting ==> "Hello, World!"
# 定义方法
jshell> int sum(int a, int b) { return a + b; }
| 已创建 方法 sum(int,int)
# 使用方法
jshell> sum(10, 20)
$4 ==> 30
# 查看已定义的变量和方法
jshell> /vars
| String greeting = "Hello, World!"
| int $4 = 30
jshell> /methods
| int sum(int,int)
应用场景
- 快速原型开发
// 测试新API
jshell> import java.net.http.*
jshell> var client = HttpClient.newHttpClient()
jshell> var request = HttpRequest.newBuilder().uri(URI.create("https://example.com")).build()
jshell> var response = client.send(request, HttpResponse.BodyHandlers.ofString())
jshell> response.body()
- 教学和学习
// 演示语言特性
jshell> var list = List.of(1, 2, 3, 4, 5)
jshell> list.stream().filter(n -> n % 2 == 0).map(n -> n * n).toList()
$2 ==> [4, 16]
- API探索
// 探索类方法
jshell> /imports
| import java.io.*
| import java.math.*
| import java.net.*
// ...
jshell> String.class.getMethods()
// 显示String类的所有方法
集合工厂方法
特性概述
Java 9引入了创建不可变集合的便捷工厂方法,使创建小型集合实例更加简洁。
技术细节
新增的工厂方法包括:
List.of()
Set.of()
Map.of()
和Map.ofEntries()
// 创建不可变List
List<String> list = List.of("Java", "Python", "JavaScript");
// 创建不可变Set
Set<Integer> set = Set.of(1, 2, 3, 4, 5);
// 创建不可变Map (最多10个键值对)
Map<String, Integer> map = Map.of(
"Java", 1995,
"Python", 1991,
"JavaScript", 1995
);
// 创建不可变Map (超过10个键值对)
Map<String, Integer> largeMap = Map.ofEntries(
Map.entry("Java", 1995),
Map.entry("Python", 1991),
Map.entry("JavaScript", 1995),
// ...更多条目
);
这些集合有以下特点:
- 不可变(不支持添加、删除或替换元素)
- 不允许null元素
- 结构紧凑,内存效率高
- 对于Map.of(),最多支持10个键值对
应用场景
- 常量集合定义
// 定义常量列表
private static final List<String> SUPPORTED_LANGUAGES =
List.of("Java", "Kotlin", "Scala", "Groovy");
- 方法返回值
// 返回不可变集合
public List<User> getDefaultUsers() {
return List.of(
new User("admin", Role.ADMIN),
new User("guest", Role.GUEST)
);
}
- 参数传递
// 传递不可变集合作为参数
processItems(Set.of("item1", "item2", "item3"));
接口私有方法
特性概述
Java 9允许在接口中定义私有方法,进一步增强了接口的封装能力,使默认方法的代码复用更加便捷。
技术细节
接口可以定义两种私有方法:
- 私有实例方法:供默认方法调用
- 私有静态方法:供静态方法和默认方法调用
public interface Logger {
// 公共抽象方法
void log(String message);
// 默认方法
default void logInfo(String message) {
log(addSeverity("INFO", message));
}
default void logWarning(String message) {
log(addSeverity("WARNING", message));
}
default void logError(String message) {
log(addSeverity("ERROR", message));
}
// 私有方法 - 供默认方法复用
private String addSeverity(String severity, String message) {
return "[" + severity + "] " + message;
}
// 私有静态方法
private static String getCurrentTimestamp() {
return LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
}
应用场景
- 代码复用
public interface PaymentProcessor {
void processPayment(Payment payment);
default void processDebitPayment(DebitPayment payment) {
validatePayment(payment);
processPayment(payment);
}
default void processCreditPayment(CreditPayment payment) {
validatePayment(payment);
processPayment(payment);
}
// 私有辅助方法
private void validatePayment(Payment payment) {
if (payment.getAmount() <= 0) {
throw new IllegalArgumentException("Payment amount must be positive");
}
// 其他验证逻辑
}
}
- 接口实现辅助
public interface DataProcessor {
void process(List<String> data);
default void processFile(Path filePath) throws IOException {
process(readLines(filePath));
}
// 私有辅助方法
private List<String> readLines(Path filePath) throws IOException {
return Files.readAllLines(filePath);
}
}
改进的Stream API
特性概述
Java 9对Stream API进行了增强,添加了几个新的方法,使流处理更加灵活和强大。
技术细节
新增的Stream方法包括:
takeWhile()
: 依次获取满足条件的元素,直到遇到第一个不满足条件的元素dropWhile()
: 依次丢弃满足条件的元素,直到遇到第一个不满足条件的元素ofNullable()
: 创建一个包含单个元素的流,如果元素为null则创建空流iterate()
: 增强版的迭代方法,支持终止条件
// takeWhile 示例
Stream.of(1, 2, 3, 4, 5, 1, 2)
.takeWhile(n -> n < 4) // 获取元素直到遇到 >= 4 的元素
.forEach(System.out::println); // 输出: 1, 2, 3
// dropWhile 示例
Stream.of(1, 2, 3, 4, 5, 1, 2)
.dropWhile(n -> n < 4) // 丢弃元素直到遇到 >= 4 的元素
.forEach(System.out::println); // 输出: 4, 5, 1, 2
// ofNullable 示例
Stream<String> stream = Stream.ofNullable(getNullableValue());
// 如果getNullableValue()返回null,则stream是空流
// 带终止条件的iterate
Stream.iterate(1, n -> n <= 100, n -> n * 2) // 从1开始,每次乘2,直到超过100
.forEach(System.out::println); // 输出: 1, 2, 4, 8, 16, 32, 64
应用场景
- 处理有序数据
// 处理有序日志,直到遇到错误日志
logs.stream()
.takeWhile(log -> log.getLevel() != LogLevel.ERROR)
.forEach(System.out::println);
- 数据分段处理
// 跳过所有小于阈值的数据,处理其余数据
measurements.stream()
.dropWhile(m -> m.getValue() < threshold)
.forEach(processor::process);
- 可能为空的数据处理
// 处理可能为null的用户数据
Stream.ofNullable(getUserData())
.flatMap(Collection::stream)
.forEach(this::processUserData);
其他重要特性
HTTP/2客户端 (孵化)
Java 9引入了新的HTTP客户端API (incubator),支持HTTP/2和WebSocket:
// 创建HTTP客户端
HttpClient client = HttpClient.newHttpClient();
// 构建请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.GET()
.build();
// 发送同步请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());
// 发送异步请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join(); // 等待完成
// POST请求示例
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/users"))
.timeout(Duration.ofSeconds(30))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"张三\",\"age\":30}"))
.build();
多版本JAR文件
Java 9支持创建包含针对不同Java版本的类文件的JAR包:
multi-release-jar/
├── META-INF/
│ └── versions/
│ ├── 9/
│ │ └── com/example/
│ │ └── MyClass.class # Java 9特定实现
│ └── 10/
│ └── com/example/
│ └── MyClass.class # Java 10特定实现
└── com/
└── example/
└── MyClass.class # 基础实现
改进的Javadoc
Java 9的Javadoc支持HTML5和搜索功能,并添加了新的标签:
/**
* 这是一个示例类
*
* @apiNote 这个API的使用注意事项
* @implSpec 实现规范说明
* @implNote 实现细节说明
*/
public class Example {
// ...
}
Java 10 核心特性解析
Java 10于2018年3月发布,是Java采用新的六个月发布周期后的第一个版本,虽然特性较少,但引入了一些实用的改进。
局部变量类型推断 (var)
特性概述
Java 10引入了局部变量类型推断,允许使用var
关键字声明局部变量,编译器会根据变量的初始化表达式自动推断其类型。
技术细节
var
关键字的使用有以下限制:
- 只能用于局部变量声明,不能用于方法参数、字段、返回类型等
- 声明时必须初始化变量
- 不能将值设为null
- 不能用于lambda表达式的参数
// 基本用法
var text = "Hello, World!"; // 推断为String
var numbers = List.of(1, 2, 3, 4, 5); // 推断为List<Integer>
var map = new HashMap<String, Integer>(); // 推断为HashMap<String, Integer>
// 循环中使用
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
// 增强for循环
for (var item : collection) {
System.out.println(item);
}
// try-with-resources
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
// 使用reader
}
这些集合有以下特点:
- 不可变(不支持添加、删除或替换元素)
- 不允许null元素
- 结构紧凑,内存效率高
- 对于Map.of(),最多支持10个键值对
应用场景
- 减少冗长的类型声明
// 传统方式
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
// 使用var
var reader = new BufferedReader(new InputStreamReader(System.in));
- 使用匿名类
// 传统方式
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
// 使用var
var comparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
- 复杂泛型类型
// 传统方式
Map<String, List<Map<Integer, String>>> complexMap = new HashMap<>();
// 使用var
var complexMap = new HashMap<String, List<Map<Integer, String>>>();
G1垃圾收集器的并行Full GC
特性概述
Java 10将G1垃圾收集器的Full GC实现改为并行,显著提高了G1收集器在最坏情况下的性能。
技术细节
G1垃圾收集器在Java 9成为默认垃圾收集器,但其Full GC过程仍然是单线程的,这在大型堆上可能导致长时间停顿。Java 10改进了这一点:
- 使用多线程并行标记-清除-压缩算法
- 与之前的单线程实现相比,大幅减少了Full GC的停顿时间
- 通过
-XX:ParallelGCThreads
参数控制并行线程数
# 启用G1收集器(Java 9+默认启用)
java -XX:+UseG1GC -XX:ParallelGCThreads=4 MyApplication
应用场景
- 大内存服务器应用
# 为大型服务器应用配置G1
java -XX:+UseG1GC -Xms4g -Xmx4g -XX:ParallelGCThreads=8 -XX:ConcGCThreads=2 ServerApplication
- 低延迟要求的应用
# 优化低延迟应用的GC配置
java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=45 LowLatencyApp
应用类数据共享 (Application Class-Data Sharing)
特性概述
Java 10扩展了类数据共享(CDS)功能,允许将应用类放入共享存档中,减少启动时间和内存占用。
技术细节
应用类数据共享(AppCDS)的工作流程:
- 创建类列表
- 创建共享存档
- 使用共享存档启动应用
# 步骤1:生成类列表
java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=classes.lst -cp app.jar MyApp
# 步骤2:创建共享存档
java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=classes.lst -XX:SharedArchiveFile=app.jsa -cp app.jar
# 步骤3:使用共享存档启动应用
java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=app.jsa -cp app.jar MyApp
应用场景
- 微服务和容器化应用
# 为Docker容器中的微服务创建共享存档
java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=microservice.lst -XX:SharedArchiveFile=microservice.jsa -cp microservice.jar
- 频繁启动的应用
# 优化命令行工具的启动时间
java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=tool.jsa -cp tool.jar CommandLineTool
其他重要特性
基于时间的发布版本控制
Java 10开始采用基于时间的版本号格式:$FEATURE.$INTERIM.$UPDATE.$PATCH
- FEATURE:每六个月发布一次的功能版本
- INTERIM:中间版本(预留)
- UPDATE:兼容性更新版本
- PATCH:紧急修复版本
例如:Java 10.0.1表示第10个功能版本的第1个更新版本。
统一的垃圾收集器接口
Java 10引入了一个统一的垃圾收集器接口,使得实现新的垃圾收集器更加容易,并简化了现有收集器的代码。
线程局部握手
Java 10引入了线程局部握手机制,允许JVM在不停止全部线程的情况下,停止单个线程,提高了GC等操作的效率。
移除了JavaEE和CORBA模块
Java 10移除了Java EE和CORBA模块,这些模块在Java 9中已被标记为废弃:
- javax.activation
- javax.xml.bind
- javax.xml.ws
- javax.xml.ws.annotation
- javax.jws
- javax.jws.soap
- javax.transaction
- javax.xml.soap
- org.omg.CORBA
- 等等
额外的Unicode语言标签扩展
Java 10增强了java.util.Locale
类和相关的API,支持更多的BCP 47语言标签。
根证书
Java 10在JDK中添加了一组默认的根证书,提高了开箱即用的安全性.