以下是 JDK 8 至 JDK 21 中最具实用性的新特性整理,涵盖语言特性、工具类增强、性能优化等方向,附代码示例和注释说明:

一、JDK 8(2014):函数式编程与现代化API

JDK 8 是 Java 发展的里程碑版本,引入了大量颠覆性特性,至今仍是企业级项目的基础。

  1. Lambda 表达式

简化匿名内部类,支持函数式编程,使代码更简洁。

示例:用 Lambda 实现 Runnable 和 Comparator

// 传统匿名内部类

new Thread(new Runnable() {

@Override

public void run() {

System.out.println("传统方式");

}

}).start();

// Lambda 表达式(简化版)

new Thread(() -> System.out.println("Lambda 方式")).start();

// 传统 Comparator 排序

List list = Arrays.asList("banana", "apple", "cherry");

Collections.sort(list, new Comparator() {

@Override

public int compare(String a, String b) {

return a.compareTo(b);

}

});

// Lambda 排序(更简洁)

Collections.sort(list, (a, b) -> a.compareTo(b));

// 或直接使用方法引用:list.sort(String::compareTo);

  1. Stream API

提供声明式集合操作(过滤、映射、聚合等),支持并行计算。

示例:用 Stream 处理集合

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// 过滤偶数,平方后求和

int sum = numbers.stream()

.filter(n -> n % 2 == 0) // 过滤偶数

.mapToInt(n -> n * n) // 平方

.sum(); // 求和

System.out.println(sum); // 输出:2² + 4² + 6² = 4 + 16 + 36 = 56

  1. Optional 类

解决空指针异常(NPE),显式处理可能为空的值。

示例:避免空指针

public class OptionalDemo {

public static String getUsername(User user) {

// 如果 user/user.getName() 为 null,返回 "未知用户"

return Optional.ofNullable(user) // 包装可能为空的对象

.map(User::getName) // 提取 name(若 user 非空)

.orElse("未知用户"); // 最终默认值

}

public static void main(String[] args) {
User user = new User("张三");
User nullUser = null; System.out.println(getUsername(user)); // 输出:张三
System.out.println(getUsername(nullUser));// 输出:未知用户
} static class User {
private String name;
public User(String name) { this.name = name; }
public String getName() { return name; }
}

}

  1. 新的日期时间 API(java.time)

替代老旧的 Date 和 SimpleDateFormat,线程安全且设计更合理。

示例:日期时间操作

// 获取当前日期(不含时间)

LocalDate today = LocalDate.now();

System.out.println("今天:" + today); // 输出:2025-09-17

// 解析日期字符串

LocalDate birthday = LocalDate.parse("1990-05-20");

System.out.println("生日:" + birthday); // 输出:1990-05-20

// 计算两个日期的间隔(天数)

long daysBetween = ChronoUnit.DAYS.between(birthday, today);

System.out.println("距离生日已过:" + daysBetween + "天");

// 时间操作(带时区)

ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

System.out.println("上海时间:" + zonedDateTime); // 输出:2025-09-17T16:45:00+08:00[Asia/Shanghai]

二、JDK 9(2017):模块化与基础增强

JDK 9 引入了模块化系统(JPMS),并对核心类库做了多项实用改进。

  1. 模块化系统(JPMS)

通过 module-info.java 明确模块依赖,提升代码封装性和安全性。

示例:模块定义与依赖

// 模块描述文件:module-info.java

module com.example.app {

requires java.base; // 依赖基础模块(所有模块隐式依赖)

requires com.example.utils; // 显式依赖自定义工具模块

exports com.example.app.api; // 导出包供其他模块使用

}

// 模块内代码(com/example/app/api/Calculator.java)

package com.example.app.api;

public class Calculator {

public int add(int a, int b) { return a + b; }

}

  1. 不可变集合工厂方法

List、Set、Map 新增静态工厂方法(如 of()、ofEntries()),快速创建不可变集合。

示例:创建不可变集合

// 不可变 List(线程安全,无法添加/删除元素)

List immutableList = List.of("a", "b", "c");

// immutableList.add("d"); // 抛出 UnsupportedOperationException

// 不可变 Set(无重复元素)

Set immutableSet = Set.of(1, 2, 3);

// 不可变 Map(键值对固定)

Map<String, Integer> immutableMap = Map.of("one", 1, "two", 2);

// 若需多个键值对,使用 Map.ofEntries()

Map<String, Integer> map = Map.ofEntries(

entry("three", 3),

entry("four", 4)

);

  1. Stream 增强

新增 takeWhile()、dropWhile()(按条件截断流)和 ofNullable()(处理空值)。

示例:Stream 截断与空值处理

List numbers = Arrays.asList(2, 4, 6, 7, 8, 10);

// takeWhile:遇到第一个不满足条件的元素后停止处理(顺序流)

numbers.stream()

.takeWhile(n -> n % 2 == 0) // 取前三个偶数(2,4,6)

.forEach(System.out::print); // 输出:246

// dropWhile:跳过前几个满足条件的元素,直到遇到不满足的(顺序流)

numbers.stream()

.dropWhile(n -> n < 7) // 跳过 2,4,6(都小于7),从7开始

.forEach(System.out::print); // 输出:7810

// ofNullable:避免空流

Stream stream = Stream.ofNullable(null);

stream.findFirst().ifPresent(System.out::println); // 无输出(流为空)

三、JDK 10(2018):局部变量类型推断

JDK 10 引入 var 关键字,简化局部变量声明(仅适用于局部变量,不可用于方法参数或字段)。

var 局部变量类型推断

编译器自动推断变量类型,减少冗余代码。

示例:用 var 简化代码

public class VarDemo {

public static void main(String[] args) {

// 传统声明

String name = "张三";

List numbers = new ArrayList<>();

    // 使用 var(类型由编译器推断)
var nameInferred = "张三"; // 推断为 String
var numbersInferred = new ArrayList<>(); // 推断为 ArrayList<Object>(需注意类型安全)
var list = List.of(1, 2, 3); // 推断为 List<Integer> // 注意:var 不能用于方法参数或返回值类型
// public var method(var param) {} // 编译错误
}

}

四、JDK 11(2018):HTTP Client 与字符串增强

JDK 11 是长期支持(LTS)版本,新增 HTTP/2 客户端、字符串工具方法等。

  1. HTTP Client(正式版)

替代传统的 HttpURLConnection,支持 HTTP/1.1 和 HTTP/2,异步非阻塞。

示例:发送 HTTP GET 请求

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 HttpClientDemo {

public static void main(String[] args) throws Exception {

HttpClient client = HttpClient.newHttpClient();

    // 同步请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("状态码:" + response.statusCode()); // 输出:200
System.out.println("响应体:" + response.body().substring(0, 50) + "..."); // 输出部分内容 // 异步请求(返回 CompletableFuture)
CompletableFuture<HttpResponse<String>> asyncResponse = client.sendAsync(
request,
HttpResponse.BodyHandlers.ofString()
);
asyncResponse.thenAccept(res -> System.out.println("异步响应状态码:" + res.statusCode()));
}

}

  1. 字符串新增方法

String 类新增 isBlank()、strip()(去除首尾空白)、repeat() 等方法。

示例:字符串操作

String str1 = " \t hello \n ";

String str2 = "";

String str3 = "Java";

System.out.println(str1.isBlank()); // 输出:false(包含非空白字符)

System.out.println(str2.isBlank()); // 输出:true(空字符串或全空白)

System.out.println(str1.strip()); // 输出:"hello"(去除首尾空白)

System.out.println(str1.trim()); // 输出:"hello"(传统方法,不处理 \t/\n)

System.out.println(str3.repeat(3)); // 输出:"JavaJavaJava"

五、JDK 12(2019):Switch 表达式(预览)

JDK 12 引入更简洁的 Switch 表达式(预览版,JDK 14 正式发布),支持箭头语法和 yield 返回值。

Switch 表达式(JDK 14 正式)

用 -> 替代 :,支持直接返回值,避免 break 冗余。

示例:Switch 表达式

int day = 3;

String dayName;

// 传统 Switch(语句,无返回值)

switch (day) {

case 1:

dayName = "周一";

break;

case 2:

dayName = "周二";

break;

case 3:

dayName = "周三"; // 输出:周三

break;

default:

dayName = "未知";

}

// Switch 表达式(JDK 14+,可直接返回值)

dayName = switch (day) {

case 1 -> "周一";

case 2 -> "周二";

case 3 -> "周三"; // 自动返回 "周三"

default -> "未知";

};

// 复杂逻辑用 yield(需用大括号)

int numLetters = switch (dayName) {

case "周一", "周二", "周三", "周四", "周五" -> 2; // 多个值合并

case "周六", "周日" -> {

System.out.println("周末");

yield 3; // 用 yield 返回值

}

default -> throw new IllegalStateException("无效星期");

};

System.out.println("字母数:" + numLetters); // 输出:2(周三对应2)

六、JDK 16(2021):Record 与 Pattern Matching(正式)

JDK 16 是 LTS 版本,正式发布 Record(不可变数据载体)和改进的 instanceof 模式匹配。

  1. Record(正式版)

简化不可变数据类的定义(自动生成 equals()、hashCode()、toString() 等方法)。

示例:用 Record 定义数据类

// 传统方式定义不可变类

class TraditionalUser {

private final String name;

private final int age;

public TraditionalUser(String name, int age) {
this.name = name;
this.age = age;
} // 需手动实现 equals、hashCode、toString...

}

// Record 方式(一行代码搞定)

record RecordUser(String name, int age) {}

public class RecordDemo {

public static void main(String[] args) {

RecordUser user = new RecordUser("张三", 25);

System.out.println(user); // 输出:RecordUser[name=张三, age=25](自动生成 toString)

System.out.println(user.name()); // 输出:张三(自动生成访问器 name())

System.out.println(user.age()); // 输出:25

}

}

  1. Pattern Matching for instanceof(正式版)

简化 instanceof 类型检查和强制转换的代码。

示例:模式匹配 instanceof

Object obj = "Hello JDK 16";

// 传统方式

if (obj instanceof String) {

String str = (String) obj; // 需显式强制转换

System.out.println(str.length()); // 输出:11

}

// 模式匹配(JDK 16+)

if (obj instanceof String str) { // 自动转换为 String 类型并赋值给 str

System.out.println(str.length()); // 输出:11(无需显式转换)

}

七、JDK 17(2021):密封类与虚拟线程(孵化)

JDK 17 是 LTS 版本,正式发布密封类(Sealed Classes),并孵化虚拟线程(Virtual Threads)。

  1. 密封类(正式版)

限制类的继承范围(仅允许指定子类继承或实现),增强类型安全性。

示例:密封类与允许的子类

// 密封接口,仅允许 Circle 和 Rectangle 实现

public sealed interface Shape permits Circle, Rectangle {}

// 子类必须声明为 final、sealed 或 non-sealed

final class Circle implements Shape {

private final double radius;

public Circle(double r) { this.radius = r; }

public double area() { return Math.PI * radius * radius; }

}

sealed class Rectangle implements Shape permits Square {} // 子类可进一步限制

final class Square extends Rectangle {

private final double side;

public Square(double s) { this.side = s; }

public double area() { return side * side; }

}

// 模式匹配中可安全使用密封类的子类型

public static double calculateArea(Shape shape) {

return switch (shape) {

case Circle c -> c.area(); // 仅允许 Circle

case Rectangle r -> r.area(); // 仅允许 Rectangle(或其允许的子类 Square)

// 无需 default,因为 Shape 的子类已被完全限制

};

}

public static void main(String[] args) {

Shape circle = new Circle(5);

Shape square = new Square(4);

System.out.println(calculateArea(circle)); // 输出:78.5398...

System.out.println(calculateArea(square)); // 输出:16.0

}

  1. 虚拟线程(孵化,JDK 21 正式)

轻量级线程(用户态线程),大幅降低高并发场景的资源消耗(如百万级连接)。

示例:虚拟线程执行任务

public class VirtualThreadDemo {

public static void main(String[] args) {

// 创建 10 个虚拟线程

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {

for (int i = 0; i < 10; i++) {

int taskId = i;

executor.submit(() -> {

System.out.println("任务 " + taskId + " 运行在:" + Thread.currentThread());

// 模拟耗时操作

Thread.sleep(Duration.ofSeconds(1));

return taskId;

});

}

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}

}

// 输出类似:

// 任务 0 运行在:VirtualThread[#1]/runnable@123456

// 任务 1 运行在:VirtualThread[#2]/runnable@7890ab

// ...(每个任务几乎同时启动)

八、JDK 21(2023):虚拟线程正式版与字符串模板

JDK 21 是 LTS 版本,虚拟线程正式发布,并新增字符串模板(String Templates)。

  1. 虚拟线程(正式版)

如前所述,虚拟线程是 JDK 21 的核心特性之一,适用于高并发 I/O 密集型场景(如 Web 服务器、数据库连接)。

  1. 字符串模板(正式版)

简化字符串拼接,支持表达式嵌入和安全转义(类似 Python 的 f-string)。

示例:字符串模板

// 定义模板(使用 StringTemplate)

String name = "张三";

int age = 25;

String message = STR."""

用户信息:

姓名:{name}

年龄:{age}

""";

System.out.println(message);

// 输出:

// 用户信息:

// 姓名:张三

// 年龄:25

  1. 外国函数接口(FFI,正式版)

通过 jdk.incubator.foreign 包安全调用本地代码(如 C/C++),替代 JNI(Java Native Interface)。

示例:调用 C 的 strlen 函数

import jdk.incubator.foreign.;

import static jdk.incubator.foreign.CLinker.
;

public class FFIExample {

public static void main(String[] args) {

try (Arena arena = Arena.ofConfined()) {

// 在本地内存中分配字符串(以 null 结尾)

MemorySegment str = arena.allocateUtf8String("Hello FFI");

        // 获取 C 的 strlen 函数指针
MemorySegment strlenFunc = CLinker.getInstance().lookup("strlen").get(); // 调用 strlen(参数:C指针)
long length = (long) CLinker.invokeExact(
strlenFunc,
FunctionDescriptor.of(CLong, CPointer),
str.address()
); System.out.println("字符串长度:" + length); // 输出:10("Hello FFI" 长度为10)
}
}

}

总结

JDK 8 后的版本持续聚焦开发效率(Lambda、Stream、Record)、性能优化(向量API、ZGC)、现代化API(日期时间、HTTP Client)和并发模型革新(虚拟线程)。实际项目中,建议优先使用 LTS 版本(如 JDK 8、11、17、21),并根据需求选择特性(如用 Record 简化数据类,用虚拟线程处理高并发)。

效率翻倍新技能:JDK8后的新特性的更多相关文章

  1. 黑马程序员_Java基础:JDK1.5后的新特性:自动拆装箱,以及注意事项

    ------- android培训.java培训.期待与您交流! ---------- 首先来看一段代码: Integer x = new Integer(4); Integer y = 4; 在JD ...

  2. JDK7和JDK8一些重要新特性

    jdk7新特性(部分) switch支持字符串 List AutoCloseable接口实现自动关闭,在try()中 新增获取环境信息的工具方法,getJavaHomeDir,getUserHomeD ...

  3. dk7和jdk8的一些新特性

    本文是我学习了解了j 的一些资料,有兴趣的大家可以浏览下下面的内容. 官方文档:http://www.oracle.com/technetwork/java/javase/jdk7-relnotes- ...

  4. JDK8~JDK11的新特性

    #JDK 1.8 新特性接口中的静态方法 只能由接口自己调用 接口中的默认方法 可以不被覆盖 #JDK 1.9 新特性(可能在JDK8中被忽略了,没来得及加)接口可以定义私有方法,但是只能让自己调用, ...

  5. JDK1.5后的新特性之一:可变参数

    Java中的可变参数 Java1.5后出现了一个新特性,即可变参数,格式为:类型 …参数 例如: 总的来说,可变参数可以当成是数组来用: public void testSum() { System. ...

  6. JDK8中的新特性

    1.lambda表达式 1.定义 Java 8 发布的最重要新特性.Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以推导出来的就可以省略了,Lambda 表达式免去了使用匿 ...

  7. JDK8之Stream新特性

    https://www.cnblogs.com/cbxBlog/p/9123106.html /** *JDK8 Stream特性 * Created by chengbx on 2018/5/27. ...

  8. jdk8新特性(文章推荐)

    文章推荐 jdk9都已经出来了,虽然很多项目都已经使用jdk8,但是很少会用到jdk8中的新特性.本人经常用的到也就是使用Stream,Lambda,但也仅仅是使用,基本不知道什么Function,C ...

  9. JDK8的新特性——Lambda表达式

    JDK8已经发布快4年的时间了,现在来谈它的新特性显得略微的有点“不合时宜”.尽管JDK8已不再“新”,但它的重要特性之一——Lambda表达式依然是不被大部分开发者所熟练运用,甚至不被开发者所熟知. ...

  10. jdk8新特性(详解)

    最近在复习外加看点面试题,jdk8的新特性虽然在项目用用到过一两个,准备系统的了解一下jdk8的常用新特性 一:Lambd表达式 也可称为闭包         引入函数式编程到Java中 为了使现有函 ...

随机推荐

  1. stm32主要用来做什么?

    STM32主要用来做什么?一个从机械转行的十年老兵血泪经验 写在前面:一个改变命运的小芯片 说起STM32,我真的是百感交集. 十年前,我还是个刚从某211大学机械专业毕业的愣头青,对嵌入式.单片机这 ...

  2. 支持5G WIFI的串口服务器

    WiFi 串口服务器(RS485 ⇌WiFi),主要实现 RS485 数据通过 WiFi 实现设备联网数据交互设备,市场主流工作在频段为2.4G和5.8G ,2.4G WiFi信号的频段处于2.400 ...

  3. 可编程Modbus网关在非标称重仪表的应用

    1.概述 上海卓岚信息科技有限公司是一家专业提供工业物联网解决方案的高新技术企业,注册商标"ZLAN".公司研发的产品:物联网芯片.串口转以太网模块.串口服务器.可编程Modbus ...

  4. sass 定义全局变量

    定义变量文件 随便写一个scss文件,比如在 src/assets/var.scss $my-color: #00b96b; 打包工具配置 不同工具 如webpack.vite有不同的处理方式加载到全 ...

  5. Ubuntu使用Certbot生成泛域名解析证书

    1. 安装Certbot sudo apt install certbot -y certbot --version certbot 2.9.0 2. 域名验证 泛域名的验证采用DNS01的验证方式, ...

  6. 使用IntelliJ IDEA 配置Maven项目

    今天准备写个Java Web项目,决定用新安装的IntelliJ IDEA来试试,毕竟听别人说这个IDEA管理Maven项目比Eclipse方便,于是乎在网上找到了一篇超级有用的入门级配置教程,接下来 ...

  7. ubuntu 安装flash

    安装一直失败 转载 ubuntu 14.04安装flash无效的解决方法 144 作者 Devid 关注 2015.11.20 20:44* 字数 350 阅读 1701评论 1喜欢 0 原文出处:h ...

  8. 剑指offer 22 链表中倒数第K个节点.

    简介 链表中倒数第K个节点. 思路 双指针, 然后一个指针延迟运行. code class Solution { public: ListNode* getKthFromEnd(ListNode* h ...

  9. Shell是什么?--九五小庞

    Shell Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这个应用程序提供了一个界面, ...

  10. PACS实施基础知识