Java各个版本的新特性

Java各个版本的新特性

概述

Java自1995年发布以来,经历了多个重要版本的迭代。每个版本都引入了新的特性和改进,本文档总结了从Java 8到最新版本的主要新特性。

Java 8 (LTS) - 2014年3月

Lambda表达式

java
// 传统方式
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.sort(new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
});

// Lambda表达式
names.sort((a, b) -> a.compareTo(b));
names.sort(String::compareTo); // 方法引用
// 传统方式
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.sort(new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
});

// Lambda表达式
names.sort((a, b) -> a.compareTo(b));
names.sort(String::compareTo); // 方法引用

Stream API

java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 过滤和转换
List<String> result = names.stream()
    .filter(name -> name.length() > 3)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

// 聚合操作
Optional<String> longest = names.stream()
    .max(Comparator.comparing(String::length));
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 过滤和转换
List<String> result = names.stream()
    .filter(name -> name.length() > 3)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

// 聚合操作
Optional<String> longest = names.stream()
    .max(Comparator.comparing(String::length));

接口默认方法

java
public interface Vehicle {
    void start();
    
    // 默认方法
    default void stop() {
        System.out.println("Vehicle stopped");
    }
    
    // 静态方法
    static void checkEngine() {
        System.out.println("Engine checked");
    }
}
public interface Vehicle {
    void start();
    
    // 默认方法
    default void stop() {
        System.out.println("Vehicle stopped");
    }
    
    // 静态方法
    static void checkEngine() {
        System.out.println("Engine checked");
    }
}

Optional类

java
Optional<String> optional = Optional.ofNullable(getString());

// 避免空指针异常
optional.ifPresent(System.out::println);

// 提供默认值
String result = optional.orElse("default");

// 链式调用
String processed = optional
    .filter(s -> s.length() > 5)
    .map(String::toUpperCase)
    .orElse("SHORT");
Optional<String> optional = Optional.ofNullable(getString());

// 避免空指针异常
optional.ifPresent(System.out::println);

// 提供默认值
String result = optional.orElse("default");

// 链式调用
String processed = optional
    .filter(s -> s.length() > 5)
    .map(String::toUpperCase)
    .orElse("SHORT");

新的日期时间API

java
// LocalDate, LocalTime, LocalDateTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = dateTime.format(formatter);

// 计算
LocalDate nextWeek = date.plusWeeks(1);
long daysBetween = ChronoUnit.DAYS.between(date, nextWeek);
// LocalDate, LocalTime, LocalDateTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = dateTime.format(formatter);

// 计算
LocalDate nextWeek = date.plusWeeks(1);
long daysBetween = ChronoUnit.DAYS.between(date, nextWeek);

Java 9 - 2017年9月

模块系统(Project Jigsaw)

java
// module-info.java
module com.example.myapp {
    requires java.base;
    requires java.logging;
    exports com.example.myapp.api;
}
// module-info.java
module com.example.myapp {
    requires java.base;
    requires java.logging;
    exports com.example.myapp.api;
}

JShell(交互式编程环境)

bash
$ jshell
jshell> int x = 10
x ==> 10
jshell> System.out.println("Hello " + x)
Hello 10
$ jshell
jshell> int x = 10
x ==> 10
jshell> System.out.println("Hello " + x)
Hello 10

集合工厂方法

java
// 不可变集合
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
// 不可变集合
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);

接口私有方法

java
public interface MyInterface {
    default void method1() {
        commonMethod();
    }
    
    default void method2() {
        commonMethod();
    }
    
    // 私有方法
    private void commonMethod() {
        System.out.println("Common logic");
    }
}
public interface MyInterface {
    default void method1() {
        commonMethod();
    }
    
    default void method2() {
        commonMethod();
    }
    
    // 私有方法
    private void commonMethod() {
        System.out.println("Common logic");
    }
}

Java 10 - 2018年3月

局部变量类型推断(var)

java
// 类型推断
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();

// 在循环中使用
for (var item : list) {
    System.out.println(item);
}
// 类型推断
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();

// 在循环中使用
for (var item : list) {
    System.out.println(item);
}

应用程序类数据共享(AppCDS)

提高应用启动时间和减少内存占用。

Java 11 (LTS) - 2018年9月

字符串新方法

java
String str = "  Hello World  ";

// 判断是否为空白
boolean isBlank = str.isBlank();

// 去除首尾空白
String stripped = str.strip();

// 重复字符串
String repeated = "Java".repeat(3); // "JavaJavaJava"

// 按行分割
Stream<String> lines = "Line1\nLine2\nLine3".lines();
String str = "  Hello World  ";

// 判断是否为空白
boolean isBlank = str.isBlank();

// 去除首尾空白
String stripped = str.strip();

// 重复字符串
String repeated = "Java".repeat(3); // "JavaJavaJava"

// 按行分割
Stream<String> lines = "Line1\nLine2\nLine3".lines();

HTTP客户端API

java
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .header("Content-Type", "application/json")
    .GET()
    .build();

HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .header("Content-Type", "application/json")
    .GET()
    .build();

HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());

运行单文件源代码

bash
# 直接运行Java源文件,无需编译
java HelloWorld.java
# 直接运行Java源文件,无需编译
java HelloWorld.java

Java 12 - 2019年3月

Switch表达式(预览)

java
// 传统switch
String result;
switch (day) {
    case MONDAY:
    case FRIDAY:
        result = "Working day";
        break;
    case SATURDAY:
    case SUNDAY:
        result = "Weekend";
        break;
    default:
        result = "Unknown";
}

// 新的switch表达式
String result = switch (day) {
    case MONDAY, FRIDAY -> "Working day";
    case SATURDAY, SUNDAY -> "Weekend";
    default -> "Unknown";
};
// 传统switch
String result;
switch (day) {
    case MONDAY:
    case FRIDAY:
        result = "Working day";
        break;
    case SATURDAY:
    case SUNDAY:
        result = "Weekend";
        break;
    default:
        result = "Unknown";
}

// 新的switch表达式
String result = switch (day) {
    case MONDAY, FRIDAY -> "Working day";
    case SATURDAY, SUNDAY -> "Weekend";
    default -> "Unknown";
};

Java 13 - 2019年9月

文本块(预览)

java
// 传统字符串
String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello World</p>\n" +
              "    </body>\n" +
              "</html>";

// 文本块
String html = """
              <html>
                  <body>
                      <p>Hello World</p>
                  </body>
              </html>
              """;
// 传统字符串
String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello World</p>\n" +
              "    </body>\n" +
              "</html>";

// 文本块
String html = """
              <html>
                  <body>
                      <p>Hello World</p>
                  </body>
              </html>
              """;

Java 14 - 2020年3月

Switch表达式(正式)

Switch表达式从预览特性转为正式特性。

记录类型(预览)

java
// 传统类
public class Point {
    private final int x;
    private final int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    // getter, equals, hashCode, toString...
}

// 记录类型
public record Point(int x, int y) {}
// 传统类
public class Point {
    private final int x;
    private final int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    // getter, equals, hashCode, toString...
}

// 记录类型
public record Point(int x, int y) {}

instanceof模式匹配(预览)

java
// 传统方式
if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.length());
}

// 模式匹配
if (obj instanceof String str) {
    System.out.println(str.length());
}
// 传统方式
if (obj instanceof String) {
    String str = (String) obj;
    System.out.println(str.length());
}

// 模式匹配
if (obj instanceof String str) {
    System.out.println(str.length());
}

Java 15 - 2020年9月

文本块(正式)

文本块从预览特性转为正式特性。

密封类(预览)

java
public sealed class Shape 
    permits Circle, Rectangle, Triangle {
}

public final class Circle extends Shape {}
public final class Rectangle extends Shape {}
public final class Triangle extends Shape {}
public sealed class Shape 
    permits Circle, Rectangle, Triangle {
}

public final class Circle extends Shape {}
public final class Rectangle extends Shape {}
public final class Triangle extends Shape {}

Java 16 - 2021年3月

记录类型(正式)

记录类型从预览特性转为正式特性。

instanceof模式匹配(正式)

instanceof模式匹配从预览特性转为正式特性。

Stream.toList()

java
List<String> list = stream
    .filter(s -> s.length() > 3)
    .toList(); // 新方法,返回不可变列表
List<String> list = stream
    .filter(s -> s.length() > 3)
    .toList(); // 新方法,返回不可变列表

Java 17 (LTS) - 2021年9月

密封类(正式)

密封类从预览特性转为正式特性。

随机数生成器增强

java
RandomGenerator generator = RandomGenerator.of("Xoshiro256PlusPlus");
int randomInt = generator.nextInt(1, 100);
RandomGenerator generator = RandomGenerator.of("Xoshiro256PlusPlus");
int randomInt = generator.nextInt(1, 100);

移除实验性AOT和JIT编译器

移除了实验性的AOT编译器和Graal JIT编译器。

Java 18 - 2022年3月

UTF-8默认字符集

UTF-8成为标准Java API的默认字符集。

简单Web服务器

bash
# 启动简单的文件服务器
jwebserver -p 8080 -d /path/to/directory
# 启动简单的文件服务器
jwebserver -p 8080 -d /path/to/directory

代码片段在Javadoc中

java
/**
 * 示例方法
 * {@snippet :
 * var list = List.of("a", "b", "c");
 * list.forEach(System.out::println);
 * }
 */
public void example() {}
/**
 * 示例方法
 * {@snippet :
 * var list = List.of("a", "b", "c");
 * list.forEach(System.out::println);
 * }
 */
public void example() {}

Java 19 - 2022年9月

虚拟线程(预览)

java
// 创建虚拟线程
Thread.startVirtualThread(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

// 使用ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> {
        // 任务代码
    });
}
// 创建虚拟线程
Thread.startVirtualThread(() -> {
    System.out.println("Virtual thread: " + Thread.currentThread());
});

// 使用ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> {
        // 任务代码
    });
}

结构化并发(孵化)

java
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Future<String> user = scope.fork(() -> findUser());
    Future<String> order = scope.fork(() -> findOrder());
    
    scope.join();           // 等待所有任务完成
    scope.throwIfFailed();  // 如果有失败则抛出异常
    
    // 使用结果
    return new Response(user.resultNow(), order.resultNow());
}
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Future<String> user = scope.fork(() -> findUser());
    Future<String> order = scope.fork(() -> findOrder());
    
    scope.join();           // 等待所有任务完成
    scope.throwIfFailed();  // 如果有失败则抛出异常
    
    // 使用结果
    return new Response(user.resultNow(), order.resultNow());
}

Java 20 - 2023年3月

作用域值(孵化)

java
public class UserContext {
    public static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
}

// 绑定值
ScopedValue.where(UserContext.USER_ID, "user123")
    .run(() -> {
        // 在这个作用域内可以访问USER_ID
        String userId = UserContext.USER_ID.get();
    });
public class UserContext {
    public static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
}

// 绑定值
ScopedValue.where(UserContext.USER_ID, "user123")
    .run(() -> {
        // 在这个作用域内可以访问USER_ID
        String userId = UserContext.USER_ID.get();
    });

Java 21 (LTS) - 2023年9月

虚拟线程(正式)

虚拟线程从预览特性转为正式特性。

字符串模板(预览)

java
String name = "World";
int value = 42;

// 字符串模板
String message = STR."Hello \{name}, value is \{value}";
String name = "World";
int value = 42;

// 字符串模板
String message = STR."Hello \{name}, value is \{value}";

序列集合

java
// 新的集合接口,提供统一的首尾访问方法
SequencedCollection<String> list = new ArrayList<>();
list.addFirst("first");
list.addLast("last");

String first = list.getFirst();
String last = list.getLast();
// 新的集合接口,提供统一的首尾访问方法
SequencedCollection<String> list = new ArrayList<>();
list.addFirst("first");
list.addLast("last");

String first = list.getFirst();
String last = list.getLast();

版本选择建议

LTS版本推荐

  • Java 8:仍被广泛使用,但逐渐过时
  • Java 11:当前主流LTS版本,推荐用于生产环境
  • Java 17:最新LTS版本,推荐新项目使用
  • Java 21:最新LTS版本,包含最新特性

升级考虑因素

  1. 兼容性:检查第三方库和框架的支持情况
  2. 性能:新版本通常有性能改进
  3. 安全性:新版本包含安全修复
  4. 特性需求:是否需要新版本的特定特性
  5. 维护成本:团队学习和迁移成本

总结

Java持续演进,每个版本都带来新的特性和改进。对于生产环境,建议使用LTS版本以获得长期支持。同时,了解新特性有助于编写更简洁、高效的代码。选择Java版本时应综合考虑项目需求、团队能力和生态系统支持情况。