Java9新特性:平台与JVM日志及其他改进
立即解锁
发布时间: 2025-08-18 02:22:48 阅读量: 2 订阅数: 8 

# Java 9 新特性:平台与 JVM 日志及其他改进
## 1. 平台与 JVM 日志
### 1.1 日志命令示例
以下命令使用主机名、正常运行时间、日志级别和标签作为装饰,记录带有 `startuptime` 标签的消息。其他设置均采用默认值,它将记录信息级别及以上的消息,并将其输出到标准输出:
```
C:\Java9Revealed>java -Xlog:startuptime::hostname,uptime,level,tags
--module-path com.jdojo.intro\dist --module com.jdojo.intro/com.jdojo.intro.Welcome
```
执行该命令后,会输出一系列启动时间相关的日志信息,例如:
```
[0.015s][kishori][info][startuptime] StubRoutines generation 1, 0.0002574 secs
[0.019s][kishori][info][startuptime] Genesis, 0.0038339 secs
...
```
### 1.2 日志系统概述
JDK 9 对平台类(JDK 类)和 JVM 组件的日志系统进行了全面改进:
- **平台日志 API**:允许指定自定义日志记录器,供所有平台类使用。该 API 由 `java.lang.System.LoggerFinder` 类和 `java.lang.System.Logger` 接口组成。
- `System.Logger` 接口的实例代表一个平台日志记录器。
- `System.LogFinder` 类是一个服务接口,需要为其提供实现,该实现返回 `System.Logger` 接口的实例。
- 可以使用 `java.lang.System` 类中的 `getLogger()` 方法获取 `System.Logger`。应用程序中的模块必须包含 `provides` 语句,指定 `System.LogFinder` 服务接口的实现,否则将使用默认日志记录器。
- **JVM 日志命令行选项**:新增 `-Xlog` 选项,可用于记录所有 JVM 组件的消息。该选项允许指定消息类型、消息严重级别、日志目标、日志消息的装饰以及日志文件属性。消息通过一组标签进行标识,`System.Logger.Level` 枚举的常量指定消息的严重级别,日志目标可以是标准输出、标准错误输出或文件。
## 2. JDK 9 的其他变化
### 2.1 下划线成为关键字
在 JDK 9 中,下划线 `_` 成为关键字,不能单独用作单字符标识符(如变量名、方法名、类型名等),但可以在多字符标识符中使用。例如以下代码:
```java
// UnderscoreTest.java
package com.jdojo.misc;
public class UnderscoreTest {
public static void main(String[] args) {
// 使用下划线作为标识符,在 JDK 8 中是编译时警告,在 JDK 9 中是编译时错误
int _ = 19;
System.out.println(_);
// 在下划线用于多字符标识符,在 JDK 8 和 JDK 9 中都没问题
final int FINGER_COUNT = 20;
final String _prefix = "Sha";
}
}
```
在 JDK 8 中编译上述代码会产生警告,而在 JDK 9 中会产生编译错误。目前 JDK 9 只是限制其作为标识符使用,未来版本可能会赋予其特殊含义。
### 2.2 改进的 try - with - resources 块
#### 2.2.1 JDK 7 引入的 try - with - resources
JDK 7 引入了 `AutoCloseable` 接口和 `try - with - resources` 块,用于管理可自动关闭的资源。使用步骤如下:
1. 在块的开头将资源的引用分配给新声明的变量。
2. 在块的主体中使用该资源。
3. 当块的主体退出时,代表资源的变量的 `close()` 方法将自动调用。
在 JDK 7 之前,管理可关闭资源的代码如下:
```java
/* 早于 JDK 7 */
Resource res = null;
try{
// 创建资源
res = new Resource();
// 使用 res 进行操作
} finally {
try {
if(res != null) {
res.close();
}
} catch(Exception e) {
e.printStackTrace();
}
}
```
JDK 7 引入 `try - with - resources` 后,代码可以简化为:
```java
try (Resource res = new Resource()) {
// 使用 res 进行操作
}
```
#### 2.2.2 JDK 9 的改进
JDK 7 和 8 要求在 `try - with - resources` 块中声明引用资源的变量。而 JDK 9 移除了这个限制,现在可以使用最终或有效最终的变量来管理资源。
最终变量是使用 `final` 关键字显式声明的变量,有效最终变量是初始化后值不再改变的变量。例如:
```java
// res 是显式最终变量
final Resource res = new Resource();
```
```java
void doSomething() {
// res 是有效最终变量
Resource res = new Resource();
res.useMe();
}
```
在 JDK 9 中,可以这样使用:
```java
Resource res = new Resource();
try (res) {
// 使用 res 进行操作
}
```
如果有多个资源,可以这样管理:
```java
Resource res1 = new Resource();
Resource res2 = new Resource();
try (res1; res2) {
// 使用 res1 和 res2 进行操作
}
```
也可以混合使用 JDK 8 和 JDK 9 的方法:
```java
Resource res1 = new Resource();
Resource res2 = new Resource();
try (res1; res2; Resource res3 = new Resource()) {
// 使用 res1、res2 和 res3 进行操作
}
```
以下是一个完整的示例:
```java
// Resource.java
package com.jdojo.misc;
public class Resource implements AutoCloseable {
private final long id;
public Resource(long id) {
this.id = id;
System.out.printf("Created resource %d.%n", this.id);
}
public void useIt() {
System.out.printf("Using resource %d.%n", this.id);
}
@Override
public void close() {
System.out.printf("Closing resource %d.%n", this.id);
}
}
```
```java
// ResourceTest.java
package com.jdojo.misc;
public class ResourceTest {
public static void main(String[] args) {
Resource r1 = new Resource(1);
Resource r2 = new Resource(2);
try(r1; r2) {
r1.useIt();
r2.useIt();
r2.useIt();
}
useResource(new Resource(3));
}
public static void useResource(Resource res) {
try(res; Resource res4 = new Resource(4)) {
res.useIt();
res4.useIt();
}
}
}
```
### 2.3 匿名类中的钻石运算符
#### 2.3.1 JDK 7 引入的钻石运算符
JDK 7 引入了钻石运算符 `<>`,用于调用泛型类的构造函数,只要编译器能够推断出泛型类型。例如:
```java
// 显式指定泛型类型
List<String> list1 = new ArrayList<String>();
// 编译器推断 ArrayList<> 为 ArrayList<String>
List<String> list2 = new ArrayList<>();
```
#### 2.3.2 JDK 7 和 8 的限制
JDK 7 和 8 不允许在创建匿名类时使用钻石运算符。例如以下代码会产生编译错误:
```java
// 在 JDK 7 和 8 中是编译时错误
Callable<Integer> c = new Callable<>() {
@Override
public Integer call() {
return 100;
}
};
```
#### 2.3.3 JDK 9 的支持
JDK 9 支持在匿名类中使用钻石运算符,只要推断的类型是可表示的。可表示的类型是可以在 Java 程序中书写的类型,不可表示的类型则不能在 Java 程序中声明。例如:
```java
// 在 JDK 7 和 8 中是编译时错误,在 JDK 9 中允许
Callable<Integer> c = new Callable<>() {
@Override
public Integer call() {
return 100;
}
};
```
但如果推断的类型是不可表示的,即使在 JDK 9 中也不能使用钻石运算符。例如:
```java
// 在 JDK 9 中是编译时错误
Magic<?> m2 = new Magic<>(){
// 更多代码
};
```
### 2.4 接口中的私有方法
#### 2.4.1 JDK 8 的局限
JDK 8 引入了接口的静态和默认方法,但如果这些方法中需要多次执行相同的逻辑,只能重复逻辑或将逻辑移到另一个类中。例如以下接口:
```java
// Alphabet.java
package com.jdojo.misc;
public interface Alphabet {
default boolean isAtOddPos(char c) {
if (!Character.isLetter(c)) {
throw new RuntimeException("Not a letter: " + c);
}
char uc = Character.toUpperCase(c);
int pos = uc - 64;
return pos % 2 == 1;
}
default boolean isAtEvenPos(char c) {
```
0
0
复制全文
相关推荐










