【工作记录】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各个版本的新特性信息,并给出了一些简单示例。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

泽济天下

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

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

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

打赏作者

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

抵扣说明:

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

余额充值