Skip to content

JDK 9-11 特性详解

JDK 9、10和11是Java语言发展的重要版本,引入了许多新特性和改进。本文将详细介绍这些版本的主要特性,并通过示例代码来说明其用法。

JDK 9 特性

1. 模块系统 (Project Jigsaw)

模块系统是JDK 9最显著的特性,它允许将代码组织成模块,每个模块都有明确的依赖关系。

模块定义

模块通过module-info.java文件定义:

java
module com.example.mymodule {
    requires java.base;
    requires java.sql;
    exports com.example.mymodule.api;
    opens com.example.mymodule.impl to com.example.othermodule;
}

示例

步骤1: 创建模块

  1. 创建目录结构:

    mymodule/
    ├── src/
    │   └── com.example.mymodule/
    │       ├── module-info.java
    │       └── com/
    │           └── example/
    │               └── mymodule/
    │                   ├── api/
    │                   │   └── GreetingService.java
    │                   └── impl/
    │                       └── GreetingServiceImpl.java
  2. 编写module-info.java

    java
    module com.example.mymodule {
        exports com.example.mymodule.api;
    }
  3. 编写GreetingService.java

    java
    package com.example.mymodule.api;
    
    public interface GreetingService {
        String greet(String name);
    }
  4. 编写GreetingServiceImpl.java

    java
    package com.example.mymodule.impl;
    
    import com.example.mymodule.api.GreetingService;
    
    public class GreetingServiceImpl implements GreetingService {
        @Override
        public String greet(String name) {
            return "Hello, " + name + "!";
        }
    }

步骤2: 使用模块

  1. 创建另一个模块:

    app/
    ├── src/
    │   └── com.example.app/
    │       ├── module-info.java
    │       └── com/
    │           └── example/
    │               └── app/
    │                   └── Main.java
  2. 编写module-info.java

    java
    module com.example.app {
        requires com.example.mymodule;
    }
  3. 编写Main.java

    java
    package com.example.app;
    
    import com.example.mymodule.api.GreetingService;
    import com.example.mymodule.impl.GreetingServiceImpl;
    
    public class Main {
        public static void main(String[] args) {
            GreetingService service = new GreetingServiceImpl();
            System.out.println(service.greet("World"));
        }
    }

2. 接口中的私有方法

JDK 9允许在接口中定义私有方法,用于接口内部的代码复用。

示例

java
interface MyInterface {
    default void defaultMethod() {
        privateMethod();
        System.out.println("Default method");
    }
    
    private void privateMethod() {
        System.out.println("Private method");
    }
}

class MyClass implements MyInterface {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.defaultMethod();
    }
}
// 输出:
// Private method
// Default method

3. 改进的Stream API

JDK 9为Stream API添加了几个新方法:

  • takeWhile(Predicate): 从流的开始获取元素,直到满足条件
  • dropWhile(Predicate): 从流的开始丢弃元素,直到满足条件
  • ofNullable(T): 创建一个可能包含null的流
  • iterate(T, Predicate, UnaryOperator): 创建一个有限的流

示例

java
// takeWhile
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> takeWhileList = numbers.stream()
    .takeWhile(n -> n < 5)
    .collect(Collectors.toList());
System.out.println(takeWhileList); // 输出: [1, 2, 3, 4]

// dropWhile
List<Integer> dropWhileList = numbers.stream()
    .dropWhile(n -> n < 5)
    .collect(Collectors.toList());
System.out.println(dropWhileList); // 输出: [5, 6, 7, 8, 9, 10]

// ofNullable
Stream<String> stream1 = Stream.ofNullable("Hello");
Stream<String> stream2 = Stream.ofNullable(null);
System.out.println(stream1.count()); // 输出: 1
System.out.println(stream2.count()); // 输出: 0

// iterate
Stream<Integer> limitedStream = Stream.iterate(1, n -> n <= 10, n -> n + 1);
limitedStream.forEach(System.out::print); // 输出: 12345678910

4. 不可变集合工厂方法

JDK 9为集合框架添加了工厂方法,用于创建不可变集合。

示例

java
// 创建不可变List
List<String> immutableList = List.of("a", "b", "c");

// 创建不可变Set
Set<String> immutableSet = Set.of("a", "b", "c");

// 创建不可变Map
Map<String, Integer> immutableMap = Map.of(
    "a", 1,
    "b", 2,
    "c", 3
);

// 创建不可变Map(键值对超过10个)
Map<String, Integer> largeImmutableMap = Map.ofEntries(
    Map.entry("a", 1),
    Map.entry("b", 2),
    Map.entry("c", 3),
    // 可以添加更多键值对
    Map.entry("z", 26)
);

5. HTTP/2 客户端

JDK 9引入了新的HTTP客户端API,支持HTTP/2和WebSocket。

示例

java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;

public class HttpClientExample {
    public static void main(String[] args) throws Exception {
        // 创建HTTP客户端
        HttpClient client = HttpClient.newHttpClient();
        
        // 创建请求
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.github.com/users/octocat"))
            .build();
        
        // 发送同步请求
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("Status code: " + response.statusCode());
        System.out.println("Body: " + response.body());
        
        // 发送异步请求
        CompletableFuture<HttpResponse<String>> future = client.sendAsync(
            request, HttpResponse.BodyHandlers.ofString()
        );
        future.thenApply(HttpResponse::body)
              .thenAccept(System.out::println);
    }
}

JDK 10 特性

1. 局部变量类型推断 (var关键字)

JDK 10引入了var关键字,允许编译器推断局部变量的类型。

示例

java
// 传统方式
String message = "Hello";
List<String> names = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

// 使用var
var messageVar = "Hello";
var namesVar = new ArrayList<String>();
var mapVar = new HashMap<String, Integer>();

// 与lambda表达式结合
var supplier = (Supplier<String>) () -> "Hello";
var function = (Function<Integer, String>) n -> "Number: " + n;

// 与流结合
var stream = List.of(1, 2, 3).stream();
var result = stream.filter(n -> n > 1)
                   .map(n -> n * 2)
                   .collect(Collectors.toList());

2. 并行全垃圾收集器 (G1)

JDK 10使G1成为默认的垃圾收集器,替代了之前的Parallel GC。

3. 其他改进

  • Application Class-Data Sharing: 允许在多个JVM之间共享类数据,减少启动时间和内存占用
  • Thread-Local Handshakes: 允许在不停止整个线程的情况下执行线程回调
  • Time-Based Release Versioning: 引入新的版本号方案,格式为$FEATURE.$INTERIM.$UPDATE.$PATCH

JDK 11 特性

1. 标准HTTP客户端成为标准API

JDK 11将JDK 9中引入的HTTP客户端从孵化状态提升为标准API。

示例

java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class StandardHttpClientExample {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .build();
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
            .GET()
            .build();
        
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("Status: " + response.statusCode());
        System.out.println("Body: " + response.body());
    }
}

2. 字符串API增强

JDK 11为String类添加了几个新方法:

  • isBlank(): 检查字符串是否为空或只包含空白字符
  • lines(): 将字符串按行分割成流
  • strip(): 去除字符串首尾的空白字符(包括Unicode空白字符)
  • stripLeading(): 去除字符串开头的空白字符
  • stripTrailing(): 去除字符串结尾的空白字符
  • repeat(int): 将字符串重复指定次数

示例

java
// isBlank
System.out.println(" ".isBlank()); // 输出: true
System.out.println("Hello".isBlank()); // 输出: false

// lines
String text = "Line 1\nLine 2\nLine 3";
text.lines().forEach(System.out::println);
// 输出:
// Line 1
// Line 2
// Line 3

// strip
String str = "  Hello  ";
System.out.println("strip(): '" + str.strip() + "'"); // 输出: 'Hello'
System.out.println("stripLeading(): '" + str.stripLeading() + "'"); // 输出: 'Hello  '
System.out.println("stripTrailing(): '" + str.stripTrailing() + "'"); // 输出: '  Hello'

// repeat
String repeated = "Hello".repeat(3);
System.out.println(repeated); // 输出: HelloHelloHello

3. 变量类型推断增强

JDK 11允许在lambda表达式中使用var关键字。

示例

java
// 传统lambda表达式
Function<Integer, String> func1 = (Integer n) -> "Number: " + n;

// JDK 11: 使用var
Function<Integer, String> func2 = (var n) -> "Number: " + n;

// 与泛型结合
BiFunction<T, U, R> biFunc = (var t, var u) -> { /* 实现 */ };

4. 移除和废弃的特性

  • 移除:com.sun.awt.AWTUtilities、sun.misc.Unsafe.defineClass、Thread.destroy()和Thread.stop(Throwable)方法
  • 废弃:Nashorn JavaScript引擎、Pack200工具和API

5. ZGC垃圾收集器

JDK 11引入了实验性的ZGC垃圾收集器,它的特点是:

  • 低延迟(暂停时间不超过10ms)
  • 支持大堆(可达数TB)
  • 对应用吞吐量的影响小

启用ZGC

bash
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx16g MyApp

总结

JDK 9-11引入了许多重要的特性和改进,包括:

  • JDK 9:模块系统、接口私有方法、改进的Stream API、不可变集合工厂方法、HTTP/2客户端
  • JDK 10:局部变量类型推断、并行全垃圾收集器(G1)作为默认GC
  • JDK 11:标准HTTP客户端、字符串API增强、lambda表达式中的var、ZGC垃圾收集器

这些特性使得Java语言更加现代化、高效和易用,为开发者提供了更多的工具和选择。