【工作记录】JDK8到JDK21都更新了哪些新特性

前言

在软件开发的世界里,Java作为一门久经沙场且持续焕发活力的编程语言,其每一次重大版本更新都承载着开发者们的热切期待。从JDK 8到JDK 21,这是一段跨越近十年的技术革新之旅,期间引入的一系列关键新特性不仅提升了开发效率,优化了性能,还顺应了现代软件工程的潮流,诸如函数式编程、模块化设计、安全性增强以及对云原生环境的更好支持等。本篇文章将带领读者一同回顾这段历程,聚焦JDK 8至JDK 21之间每个版本的核心亮点,揭示这些特性如何重塑Java生态,助力开发者们构建更为高效、简洁、安全的应用程序。


关键版本介绍

  • JDK 8,作为Java历史上的一个重要里程碑,带来了深远影响。它的革新之处在于广泛引入了lambda表达式、函数式接口、Stream API等,实现了对函数式编程范式的有力支持,极大地简化了集合处理逻辑,并提高了代码可读性。同时,接口中允许定义默认方法和静态方法,打破了以往接口只能声明抽象方法的传统,促进了API设计的灵活性。此外,全新的Date-Time API和Optional类则为处理时间和潜在空值提供了更为清晰、一致的工具。

  • JDK 9标志着Java平台的模块化时代的开启,通过Project Jigsaw项目实现了JDK自身的模块化结构,使得应用可以按需打包和加载模块,降低了应用的启动时间和内存占用,增强了封装性和安全性。此版本还引入了List、Set、Map的工厂方法,如List.of(),方便创建不可变集合;JShell作为交互式编程工具,加速了原型开发与学习过程;Optional类的改进进一步完善了函数式编程体验;而多版本兼容的JAR包格式及新的Javadoc生成工具,均为开发者工作流带来了便利。

  • 后续版本如JDK 10至JDK 15,每一个迭代都在前一版本的基础上稳步前行,引入了诸如局部变量类型推断、垃圾回收器改进、ZGC实验性并发标记清除收集器、动态类文件常量、文本块(Text Blocks)、密封类与接口(Sealed Classes and Interfaces)等特性,旨在提升编译时类型安全性、运行时性能以及代码编写舒适度。例如,JDK 11的String类新增了一系列实用方法,如isBlank()strip()等,以简化字符串操作;而JDK 12至JDK 15则陆续推出了Switch表达式、模式匹配预览、Records类型等语言层面的增强,持续降低冗余代码并提高表达力。

  • JDK 16至JDK 21,随着Java的发展步入稳定快速发布的节奏,每个半年发布周期均带来了一批重要功能和优化。其中包括但不限于:JEP 380(Vector API),提供硬件向量计算支持;JEP 398(Foreign-Memory Access API),便于安全地直接访问外部内存;JEP 391(Strongly Encapsulate JDK Internals by Default),强化了JDK内部组件的封装;以及针对容器化、微服务场景的诸多改进,如JFR事件流(JEP 382)、隐藏类(JEP 371)等。这些特性无不体现着Java对于现代开发需求的敏锐响应和持续进化。


关键版本特性使用示例

JDK8-lambda表达式

// Before JDK 8:
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
});

// With JDK 8 Lambda expression:
Collections.sort(names, (a, b) -> a.compareTo(b));

JDK8-stream API

// Filter a list and sum all even numbers
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

long sumOfEvens = numbers.stream()
                         .filter(n -> n % 2 == 0)
                         .mapToInt(Integer::intValue)
                         .sum();

System.out.println(sumOfEvens); // Output: 12

JDK8-Optional

// Avoiding null pointer exceptions when dealing with optional values
Optional<String> optionalName = Optional.ofNullable(getUser().getName());

String greeting = optionalName.orElse("Guest");
System.out.println("Hello, " + greeting + "!");

// Or chaining methods with Optional
optionalName.ifPresent(name -> System.out.println("Found name: " + name));

JDK11-本地变量类型推断

/ Before JDK 11:
List<String> namesList = new ArrayList<>();

// With JDK 11 var:
var namesList = new ArrayList<>();

JDK11-httpClient

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

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
                                 .uri(URI.create("https://example.com"))
                                 .build();

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

System.out.println(response.statusCode());
System.out.println(response.body());

JDK17-密封类

JDK 17 中引入的密封类(Sealed Classes)是一种新的类设计机制,它允许控制类的继承层次结构,限制谁能成为其子类。密封类有助于实现更好的模块化、增加编译时类型检查、提升安全性,并有助于减少错误的继承关系。以下是几种典型的使用场景:

场景一:有限的枚举替代
当需要表示一组相关的但数量有限且已知的具体类型时,密封类可以作为传统枚举类型的有力补充。虽然枚举适用于状态固定的实例集合,但它们往往缺乏灵活性,不能携带额外的属性或行为。密封类则允许定义具有不同状态和行为的子类,同时保持类型系统的封闭性。

public sealed interface PaymentMethod permits CreditCardPayment, BankTransfer, CashOnDelivery {
    String getPaymentDescription();
}

public final class CreditCardPayment implements PaymentMethod {
    private final String cardNumber;
    // ... constructors, getters, setters, etc.
    
    @Override
    public String getPaymentDescription() {
        return "Credit Card (" + cardNumber + ")";
    }
}

public final class BankTransfer implements PaymentMethod {
    private final String accountNumber;
    // ... constructors, getters, setters, etc.

    @Override
    public String getPaymentDescription() {
        return "Bank Transfer (" + accountNumber + ")";
    }
}

public final class CashOnDelivery implements PaymentMethod {
    // No additional fields needed for this payment method

    @Override
    public String getPaymentDescription() {
        return "Cash on Delivery";
    }
}

场景二:领域建模中的受限扩展
在领域驱动设计(DDD)中,密封类可用于精确控制业务实体或值对象的扩展。例如,一个电商系统可能只允许特定类型的优惠券策略,而防止意外或恶意扩展出不符合业务规则的策略类型。

public sealed abstract class CouponStrategy permits PercentageDiscount, FixedAmountDiscount, BundleDiscount {
    public abstract BigDecimal applyDiscount(Order order);
}

public final class PercentageDiscount extends CouponStrategy {
    private final BigDecimal percentage;

    public PercentageDiscount(BigDecimal percentage) {
        this.percentage = percentage;
    }

    @Override
    public BigDecimal applyDiscount(Order order) {
        // Apply percentage-based discount logic
    }
}

// Other concrete coupon strategies follow the same pattern...

public class OrderService {
    public void applyCoupon(Order order, CouponStrategy strategy) {
        // ...
        BigDecimal discount = strategy.applyDiscount(order);
        // ...
    }
}

场景三:API设计中的类型安全
在对外提供的API中,密封类可以确保只有指定的类型能够参与到特定的逻辑流程中,从而提高类型安全性。例如,一个图形渲染库可能只允许特定类型的形状参与渲染,避免用户误传入不支持的形状类型。

public sealed interface RenderableShape permits CircleRenderable, RectangleRenderable, TriangleRenderable {
    void render(GraphicsContext context);
}

public final class CircleRenderable implements RenderableShape {
    // ...

    @Override
    public void render(GraphicsContext context) {
        // Render circle logic
    }
}

// Other renderable shapes...

public class Renderer {
    public void drawScene(List<RenderableShape> shapes, GraphicsContext context) {
        for (RenderableShape shape : shapes) {
            shape.render(context);
        }
    }
}

场景四:编译时元编程与模式匹配
结合Java 17中的模式匹配(Pattern Matching for instanceof),密封类可以在编译时进行更精细的类型检查和转换,简化代码并消除运行时类型错误。例如,一个解析JSON响应的任务可以根据不同的响应类型采取不同的处理逻辑。

public sealed interface ApiResponse permits SuccessResponse, ErrorResponse {
    // Common methods or properties...
}

public final class SuccessResponse implements ApiResponse {
    private final String data;

    // Constructor, getters, etc.
}

public final class ErrorResponse implements ApiResponse {
    private final int errorCode;
    private final String errorMessage;

    // Constructor, getters, etc.
}

public void handleApiResponse(ApiResponse response) {
    switch (response) {
        case SuccessResponse success -> {
            String data = success.getData();
            // Process successful response...
        }
        case ErrorResponse error -> {
            int errorCode = error.getErrorCode();
            String errorMessage = error.getErrorMessage();
            // Handle error response...
        }
    }
}

JDK17-instance of

if (obj instanceof String s) {
    System.out.println("String value: " + s);
} else if (obj instanceof Integer i) {
    System.out.println("Integer value: " + i);
}

JDK21-虚拟线程

import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;
import java.util.concurrent.ForkJoinPool;
import jdk.incubator.foreign.MemorySegment;

public class VirtualThreadExample {

    public static void main(String[] args) {
        // Create a virtual thread
        Thread.startVirtualThread(() -> {
            // Your concurrent task here...
        });

        // Use Project Loom features like Structured Concurrency or Foreign Function Interface
        // ...

        // Alternatively, you can also create a virtual thread pool
        ForkJoinPool virtualThreadPool = ForkJoinPool.commonPool();
        virtualThreadPool.submit(() -> {
            // Concurrent task executed on a virtual thread
        });
    }
}

JDK21-外部函数和内存API

import jdk.incubator.foreign.*;

public class ForeignFunctionExample {

    public static void main(String[] args) throws Throwable {
        // Load a shared library
        LibraryLookup lookup = LibraryLookup.ofLibraryPath("/path/to/library.so");

        // Define function signature
        FunctionDescriptor descriptor = FunctionDescriptor.ofVoid(CLinker.C_CHAR);

        // Obtain a symbol handle for the function
        SymbolHandle symbol = lookup.lookup("my_function").get();

        // Create a memory segment to hold input data
        MemorySegment inputBuffer = MemorySegment.allocateNative(1024, ResourceScope.newConfinedScope());

        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            // Call the foreign function
            CLinker.systemCLinker().callVoid(symbol, inputBuffer);

            // Access memory contents after the call
            byte resultByte = inputBuffer.getByte(0);
            System.out.println("Result byte: " + resultByte);
        }
    }
}

JDK21-Vector API

import jdk.incubator.vector.*;

public class VectorApiExample {

    public static void main(String[] args) {
        // Create a vector of integers
        VectorSpecies<Integer> intSpec = IntVector.SPECIES_PREFERRED;
        VectorMask<Integer> mask = intSpec.indexInRange(0, 4).toMask();
        Vector<Integer> vec = Vector.fromArray(intSpec, new int[]{1, 2, 3, 4}, 0);

        // Perform vector operations
        Vector<Integer> squaredVec = vec.lanewise(VectorOperators.SQUARE);
        Vector<Integer> incrementedVec = vec.add(1);

        // Extract results back to arrays
        int[] squaredArray = new int[4];
        int[] incrementedArray = new int[4];
        squaredVec.intoArray(squaredArray, 0);
        incrementedVec.intoArray(incrementedArray, 0);

        System.out.println("Squared array: " + Arrays.toString(squaredArray));
        System.out.println("Incremented array: " + Arrays.toString(incrementedArray));
    }
}

各版本主要特性清单

JDK8(March 2014)

特性名称特性描述
Lambda Expressions引入了一种简洁的函数式编程语法,允许将函数作为参数传递,简化匿名内部类的使用。
Stream API提供了一种高效处理数据集合的方式,支持流式计算、聚合操作和并行处理。
Default Methods in Interfaces接口中可以定义默认方法(带有实现的抽象方法),便于在不破坏现有实现的情况下向接口添加新功能。
Method References与lambda表达式配合使用,提供了简洁的语法来引用已有方法或构造函数。
Optional Class用于表示可能为空的值,鼓励显式处理空值情况,避免NullPointerException。
Date and Time API (JSR 310)引入全新的日期和时间API,包括LocalDate、LocalTime、LocalDateTime、ZonedDateTime等类,提供了更好的日期和时间处理能力。
Nashorn JavaScript Engine内置高性能JavaScript引擎,支持在Java应用程序中执行JavaScript代码。
Compact Profiles提供了三个精简的JRE子集,适用于资源受限的设备。
Improved Type Annotations支持使用JSR 308规范的类型注解,增强编译时的类型检查和工具支持。
Concurrency Enhancements包括StampedLock、CompletableFuture、ForkJoinPool improvements等,增强了并发编程能力。

JDK 9 (September 2017)

特性名称特性描述
Jigsaw Project (Module System)引入模块化系统(Project Jigsaw),实现了JAR包的模块化打包和运行时的模块化加载,提高了可维护性和安全性。
Reactive Streams API (JSR 356)标准化了异步非阻塞数据流处理,为响应式编程提供基础。
HTTP/2 Client新的HTTP/2协议支持的HTTP客户端API,提供了更好的性能和更低的延迟。
Process API Updates更新了java.lang.Process API,增加了对进程输入/输出流的非阻塞访问。
Multi-Resolution Images支持多分辨率图像,改进了对高DPI显示器的支持。
JShell The Java REPL提供了一个交互式的Read-Eval-Print Loop (REPL),便于快速试验Java代码片段。

JDK 10 (March 2018)

特性名称特性描述
Local-Variable Type Inference (var keyword)引入关键字var,允许编译器推断局部变量的类型。
Garbage Collector Improvements对G1垃圾收集器进行了优化,包括并行Full GC和更细粒度的内存区域划分。
Application Class-Data Sharing扩展了Class Data Sharing (CDS),支持将应用类的元数据放入共享存档,减少启动时间和内存占用。

JDK 11 (September 2018)

特性名称特性描述
HTTP Client (Standard)将之前JDK 9的实验性HTTP/2客户端API升级为正式的标准API。
Low-Overhead Heap Profiling引入低开销堆分析工具(JFR-based),无需停顿 JVM 即可进行性能分析
Epsilon Garbage Collector (No-Op GC)实验性的无操作垃圾收集器,用于性能基准测试和其他特殊情况。
Flight Recorder开放 Flight Recorder(JFR)作为标准特性,提供详细的运行时监控和故障排除数据
ZGC引入实验性的Z Garbage Collector(ZGC),旨在提供低延迟(<10ms暂停时间)、高吞吐量和大堆支持。

JDK 12 (March 2019)

特性名称特性描述
Switch Expressions (Preview)引入了开关表达式作为switch语句的扩展,允许在switch块内使用箭头语法返回值,并支持多条case语句共享相同的执行体(JEP 325)。
Microbenchmark Suite提供了一个微基准测试工具JMH(Java Microbenchmark Harness),用于测量和比较代码片段的性能(JEP 328)。
JVM Constants API添加了一组标准API以反射地访问底层运行时的常量池(JEP 334)。

JDK 13 (September 2019)

特性名称特性描述
Switch Expressions (Standard)将JDK 12中预览的开关表达式转为正式功能(JEP 354)。
Text Blocks (Preview)引入文本块(multi-line string literals)以简化编写多行字符串和嵌入式引号的处理(JEP 355)。
ZGCZ Garbage Collector能够释放未使用的堆内存返回给操作系统(JEP 376)。

JDK 14 (March 2020)

特性名称特性描述
Text Blocks (Standard)文本块从预览功能升级为标准功能(JEP 368)
Pattern Matching for instanceof (Preview)引入模式匹配语法,允许在instanceof检查后直接解构对象(JEP 305)。
Packaging Tool提供一个简单命令行工具,用于创建自包含的可执行JAR文件(JEP 343)

JDK 15 (September 2020)

特性名称特性描述
Pattern Matching for instanceof (Standard)模式匹配语法从预览变为正式功能(JEP 375)
Shenandoah: A Low-Pause-Time Garbage CollectorShenandoah垃圾收集器成为正式可用选项,旨在降低GC暂停时间(JEP 378)
Hidden Classes支持创建隐藏类,仅能通过反射访问,主要用于框架和工具(JEP 371)。

JDK 16 (March 2021)

特性名称特性描述
Records引入记录类(Record Classes),作为一种简化的类声明形式,专注于不可变数据的封装(JEP 384)
Pattern Matching for switch Statements (Preview)扩展模式匹配语法至switch语句(JEP 394)。
Foreign-Memory Access API (Incubator)提供一组低级别的API,以安全、高效地访问Java程序外部的内存(JEP 383)。

JDK 17 (September 2021)

特性名称特性描述
Sealed Classes (Standard)密封类(Sealed Classes)正式推出,限制子类化范围,增强模块性和安全性(JEP 397)。
Pattern Matching for switch Statements (Standard)模式匹配语法扩展至switch语句,允许基于对象的类型进行更简洁、类型安全的选择分支(JEP 406)
Remove the Experimental AOT and JIT Compiler移除了实验性的AOT(Ahead-of-Time)编译器和部分JIT(Just-In-Time)编译器功能(JEP 410)

JDK 18 (March 2022)

特性名称特性描述
Vector API (Second Incubator)更新了向量计算API的第二个孵化器版本,提供了硬件加速的向量化计算能力(JEP 417)
Simple Web Server提供了一个简单的内置Web服务器,方便开发者快速启动静态网页服务或HTTP端点测试(JEP 408)

JDK 19 (September 2022)

特性名称特性描述
Virtual Threads (Preview)引入虚拟线程(Project Loom的一部分),这是一种轻量级线程实现,旨在提高大规模并发编程的效率(JEP 425)
Foreign Function & Memory API (Second Incubator)外部函数与内存API进入第二个孵化器阶段,增强了对C/C++本地代码和数据的访问能力(JEP 424)。
Structured Concurrency (Incubator)结构化并发API(Project Loom的一部分)进入孵化器,旨在简化异步编程模型,提升异常处理和资源管理的清晰度(JEP 428)。

JDK 20 (March 2023)

特性名称特性描述
Foreign Function & Memory API (Third Incubator)外部函数与内存API进入第三个孵化器阶段,继续完善其功能和稳定性(假设JEP编号延续,预计为JEP 442)。
Vector API (Third Preview)向量API进入第三个预览版,进一步优化并接近最终形态(假设JEP编号延续,预计为JEP 443)。

JDK 21 (September 2023)

特性名称特性描述
Foreign Function & Memory API (Standard)外部函数与内存API预计转为正式功能,提供稳定的跨语言互操作支持(假设JEP编号延续,预计为JEP 458)
Vector API (Standard)向量API预计转为正式功能,为高性能向量化计算提供标准化支持(假设JEP编号延续,预计为JEP 459)。

结语

本文整理了jdk8-jdk21各个版本的新特性信息,并给出了一些简单示例。

希望能帮助到需要的朋友。

创作不易,欢迎一键三连。

### 回答1: JDK 17 中引入了以下新特性: 1. 模块系统:改进了 Java 应用程序的组织和部署方式。 2. 多版本兼容性(MVC):允许多个 Java 版本并存,以便在升级 JRE 时不会影响现有应用程序。 3. 已弃用的方法可以移动到不同的包中,而不会破坏现有应用程序。 4. 新的字符串方法:为了改进字符串的性能,新增了一些字符串方法。 5. 对于高精度数学的支持 6. 为了帮助应用程序更好地诊断,改进了性能数据采集和展示功能 7. 对 JFR 的改进 ( Java Flight Recorder ) 8. 对 ZGC 的改进(Z Garbage Collector) 9. 对 CDS 的改进 ( Class Data Sharing ) 10. 增加了关于线程和锁的新类 这些特性都是对JDK 16和之前版本进行改进和加强,帮助开发人员更快、更安全地构建和部署应用程序。 ### 回答2: JDK 17(Java Development Kit 17)是Java的一个版本,其中有一些新特性。以下是其中一些重要的新特性: 1. 嵌套导入语句(Nested import statements):嵌套导入允许在单个导入语句中引入多个类或静态成员。这降低了编写和维护代码的复杂性。 2. 基于源代码的Java编译(Source-Based Java Compilation):JDK 17引入了新的Java编译模式,它能够在不生成.class文件的情况下进行编译。这加快了代码的构建速度,并降低了构建过程的开销。 3. AppCDS的改进(Improved AppCDS):应用程序类数据共享(AppCDS)现在支持对持久性存储的序列化数据的压缩。这有助于减少Java堆占用的内存,并提高应用程序的性能。 4. 可垃圾回收的系统内存(Garbage Collector System Memory):JDK 17中引入了一个新的标志,允许Java堆的一部分被垃圾回收器保留,不被操作系统回收。这有助于降低内存分配和回收的成本。 5. 线程本地握手(Thread-Local Handshakes):引入了一种新的机制,使Java运行时能够在干预同步操作时与应用程序进行协商。这可以提高多线程应用程序的性能。 6. 基于JEP 356的垃圾回收器接口:JDK 17引入了与垃圾回收器相关的新接口,以支持开发人员为Java虚拟机定义自己的垃圾回收器。 这些是JDK 17中的一些新特性,它们为Java开发人员提供了更多的功能和性能改进,同时也帮助开发人员更好地编写高效的应用程序。 ### 回答3: JDK 17是Java开发工具包(JDK)的一个版本,它引入了许多新的特性和改进。以下是一些JDK 17的新特性: 1. Sealed类型:引入了一个新的关键字"sealed"来修饰类或接口,限制了允许继承或实现它们的类的范围。这样可以提供更好的封装和更严格的类使用控制。 2. 基于位的操作和无符号整数:JDK 17引入了新的方法和类,支持基于位的操作和无符号整数计算。这使得对位级数据的操作更加方便和高效。 3. 嵌套的JVM元数据:JDK 17将JVM元数据存储的格式进行了优化,引入了更紧凑和高效的方式,减少了内存使用和运行时开销。 4. 预期的垃圾收集器接口:JDK 17引入了一个新的接口,允许开发者定义自己的垃圾收集器并与JVM进行集成。这提供了更大的灵活性和定制化选项。 5. G1垃圾收集器控制:JDK 17提供了更多的控制选项来配置G1垃圾收集器,以优化性能和内存利用率。 6. 基于Root证书的标准PKI工具:JDK 17引入了基于Root证书的标准PKI(Public Key Infrastructure)工具,以加强Java应用程序的安全性和身份验证功能。 7. 统一的日志系统:JDK 17引入了一个统一的日志系统,它可以与不同的日志实现集成,并提供了更简洁和一致的API,使得日志记录和跟踪更加方便。 总之,JDK 17带来了许多新的特性和改进,包括Sealed类型、基于位的操作和无符号整数、嵌套的JVM元数据、预期的垃圾收集器接口、G1垃圾收集器控制、基于Root证书的标准PKI工具和统一的日志系统。这些新特性为开发者提供了更丰富的工具和选项,以加强Java应用程序的功能和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泽济天下

你的鼓励是我最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值