当前位置: 首页 > news >正文

从JDK 17 到 JDK 21:Java 新特性

JDK17

密封类

概念:密封类允许开发者控制哪些类可以继承或实现特定的类或接口。通过这种方式,密封类为类的继承提供了更高的安全性和可维护性。

定义:使用sealed代表该类为密封类,并用permits限制哪些类可以继承。

public sealed class Shape permits Circle, Square {// 类体
}public final class Circle extends Shape {// 类体
}public final class Square extends Shape {// 类体
}

继承类必须由final,sealed,non-sealed修饰。

  • final代表该继承类不能被任何类继承
  • sealed代表该类依然是继承类
  • non-sealed代表该类不受任何限制

优势

  • 增强可维护性: 开发者可以清晰地定义哪些类可以扩展特定类,从而更好地控制代码的变化。
  • 提高安全性: 限制类的继承可以防止不受控制的扩展,降低代码出错的概率。
  • 更好的设计: 密封类可以使类的层次结构更加明确,符合设计模式的要求。

简化instanceof

在JDK16及以前需要先进行类型判断然后强制转换获取对象

public class Main {public static void main(String[] args) {Object obj = "Hello, World!"; // String 类型的对象if (obj instanceof String) {String str = (String) obj; // 强制转换System.out.println(str.toUpperCase()); // 使用转换后的字符串}}
}

在JDK17开始可以合二为一

public class Main {public static void main(String[] args) {Object obj = "Hello, World!"; // String 类型的对象if (obj instanceof String str) { // 类型检查和转换System.out.println(str.toUpperCase()); // 直接使用 str}}
}

优点:

  • 简洁性: 通过将类型检查和转换合并为一个操作,代码更加简洁,减少了冗余。
  • 可读性: 减少了强制转换的显式写法,使得代码更易于理解。
  • 减少出错: 避免了在进行强制转换时可能出现的 ClassCastException 异常,因为编译器会确保类型检查的正确性。

增强Switch

基本示例

增强的 switch 表达式允许使用“箭头”语法 (->),这使得每个 case 分支可以直接返回一个值或执行一段代码。以下是基本的语法示例:

int day = 3; // 假设 1 = 星期一,2 = 星期二,...String dayType = switch (day) {case 1, 7 -> "Weekend"; // 支持多个 case 用逗号分隔case 2, 3, 4, 5, 6 -> "Weekday"; // 其他工作日default -> throw new IllegalArgumentException("Invalid day: " + day); // 默认情况
};System.out.println(dayType); // 输出: Weekday
代码块支持

除了简单的返回值,switch 表达式还支持代码块,你可以在 case 中包含多行代码。这时需要使用 {} 来包裹代码块,并且要使用 yield 语句返回值。

public class Main {public static void main(String[] args) {int day = 5; // 假设 1 = 星期一,2 = 星期二,...String dayType = switch (day) {case 1, 7 -> "Weekend";case 2, 3, 4, 5, 6 -> "Weekday";default -> throw new IllegalArgumentException("Invalid day: " + day);};System.out.println("Day " + day + " is a " + dayType);}
}

文本块增强

基本概念

文本块允许以更直观的方式定义多行字符串,使用三重引号(""")来包裹文本内容。这样,文本块中的换行、缩进和其他空白字符将被直接保留,增强了可读性。

基本用法

基本的文本块用法如下所示:

java复制代码String textBlock = """This is a text block.It can span multiple lines.""";
文本块的增强

在 Java 17 中,对文本块进行了增强,主要体现在以下几个方面:

换行和缩进处理

  • 自动去除公共前缀: 文本块的自动缩进特性可以去除公共前缀。这意味着,如果文本块的所有行都有相同的前缀空白(缩进),在生成的字符串中,这些空白将会被自动去除。

示例:

java复制代码String textBlock = """Line 1Line 2Line 3""";System.out.println(textBlock);

输出将是:

Line 1
Line 2
Line 3

在这个示例中,公共前缀的空白会被自动去除。

使用表达式插入文本

文本块可以与表达式结合,允许在文本块中插入动态内容。这使得文本块更加灵活和动态。

示例:

java复制代码String name = "John";
String greeting = """Hello, %s!Welcome to the Java world.""".formatted(name);System.out.println(greeting);

输出将是:

Hello, John!
Welcome to the Java world.

在这个示例中,使用了 String.formatted() 方法来插入变量。

支持 Unicode 字符

文本块支持 Unicode 字符,使得在字符串中包含特殊字符变得更加方便。例如,你可以直接在文本块中使用中文字符、表情符号等。

示例:

String unicodeTextBlock = """Hello, 世界! 🌍This is a text block with Unicode characters.""";System.out.println(unicodeTextBlock);

输出将是:

Hello, 世界! 🌍
This is a text block with Unicode characters.

JDK21

虚拟线程

为什么引入?

线程的缺点有两个:

  • 创建销毁成本高
  • 频繁切换成本高

第一个缺点已经通过线程池解决了,第二个在JDK21通过虚拟线程也得到了解决。

概念与优势

虚拟线程被设计为轻量级的执行单元,可以在 JVM 中并发执行。虚拟线程使得开发者能够创建和管理数以千计的并发任务,而无需像使用传统线程那样消耗大量资源。

优势

  • 轻量级: 虚拟线程的内存开销和启动时间都大大低于操作系统线程。这使得创建和管理虚拟线程变得更加高效。
  • 易于使用: 开发者可以使用简单的代码结构来编写并发任务,而无需管理线程的生命周期和状态。
  • 高并发: 虚拟线程允许在单个 JVM 实例中并发运行数以千计的虚拟线程,非常适合 I/O 密集型和网络应用程序。
使用

虚拟线程在代码上兼容极好,跟传统线程区别不大。

直接创建虚拟线程

public class VirtualThreadExample {public static void main(String[] args) {Thread virtualThread = Thread.ofVirtual().start(() -> {System.out.println("This is a virtual thread!");});virtualThread.join();}
}

通过线程池获取

		// 创建一个虚拟线程池ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();// 提交多个任务到虚拟线程池for (int i = 0; i < 10; i++) {final int taskId = i;executor.submit(() -> {});}// 关闭线程池executor.shutdown();

序列集合

在之前的版本中,List、Set、LinkedHashSet这些不同的集合获取首尾元素的方式不同,api不同,很折磨人。

序列集合是一类新接口,与常规集合(如 ListSet)不同,序列集合强调保持元素的插入顺序,并提供了一种更灵活的元素处理方式。

interface sequencedcollection<E>extends colection<E>{Sequencedco1lection<E> reversed(),void addLast(E);E getFirst();E getLast();E removeFirst;E removeLast();
}

有个序列集合后就不用因为不统一的api发愁了。

Record

介绍

定义: Record 是一种特殊的类,用于表示不可变的数据模型。它自动为每个字段生成构造函数、访问器(getter)和其他一些方法(如 toString()equals()hashCode())。

语法: 创建 Record 类的语法非常简洁,类似于定义普通类。记录类的定义如下:

public record Person(String name, int age) { }
特性

不可变性

  • Record 实例是不可变的,一旦创建,字段的值就不能被修改。这确保了数据的一致性和安全性,尤其是在多线程环境中。

自动生成方法

  • 构造函数: 自动生成一个构造函数,接受所有字段作为参数。
  • 访问器: 为每个字段生成一个访问器方法,名称与字段相同,但没有前缀。例如,上述 Person 记录将具有 name()age() 方法。
  • toString(): 自动生成一个 toString() 方法,返回所有字段的名称和值。
  • equals()hashCode(): 自动实现 equals()hashCode() 方法,以支持基于内容的比较和集合操作。
JDK21增强特性

record 中的泛型

Record 现在可以定义为泛型类。这使得你能够创建更具通用性和复用性的记录类:

public record Box<T>(T content) { }

sealed Record

可以将 Record 声明为 sealed,限制哪些类可以扩展该 Record

public sealed record Shape permits Circle, Square { }public record Circle(double radius) extends Shape { }public record Square(double side) extends Shape { }

记录的嵌套记录

你可以在 Record 中嵌套另一个 Record,这使得组织复杂数据模型更为简洁:

public record Address(String street, String city) { }public record Person(String name, int age, Address address) { }
使用场景
数据传输对象(DTO)

场景描述: DTO 是一种简单的对象,用于封装数据并在不同层或模块之间传递。使用 Record 可以减少样板代码。

示例代码:

// 数据传输对象
public record UserDTO(String username, String email, int age) { }public class UserService {public UserDTO getUser(int id) {// 假设从数据库获取用户数据return new UserDTO("xxx", "xxx@qq.com", 25);}
}public class Main {public static void main(String[] args) {UserService userService = new UserService();UserDTO user = userService.getUser(1);System.out.println(user.username());  System.out.println(user.email());     System.out.println(user.age());       }
}
返回类型

场景描述: 方法需要返回多个值时,使用 Record 可以将这些值组合在一起,避免使用数组或其他复杂的数据结构。

配置和设置

场景描述: 在需要表示一组配置参数或设置选项时,Record 可以提供清晰和易于维护的表示方式。

示例代码:

// 配置类
public record DatabaseConfig(String url, String username, String password) { }
总结

通过记录我们可以把之前需要创建类或者构建复杂数据结构的场景简化,记录会自动创建一些方法供我们使用,所以只需要简单声明记录类即可。

相关文章:

从JDK 17 到 JDK 21:Java 新特性

JDK17 密封类 概念&#xff1a;密封类允许开发者控制哪些类可以继承或实现特定的类或接口。通过这种方式&#xff0c;密封类为类的继承提供了更高的安全性和可维护性。 定义&#xff1a;使用sealed代表该类为密封类&#xff0c;并用permits限制哪些类可以继承。 public sea…...

【计算机网络 - 基础问题】每日 3 题(五十七)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…...

第十二章 章节练习created的应用

目录 一、引言 二、运行效果图 ​三、完整代码 一、引言 构建一个新闻的页面&#xff0c;页面在响应式数据准备好之后&#xff08;即created&#xff09;&#xff0c;就向后台接口请求获取新闻数据列表&#xff0c;然后赋值给Vue实例中的list列表&#xff0c;这个请求逻辑我…...

Unity 游戏性能优化实践:内存管理与帧率提升技巧

1. 引言 随着移动设备性能的逐步提升&#xff0c;游戏玩家对画质和流畅度的要求越来越高。优化 Unity 游戏性能不仅可以提升用户体验&#xff0c;还能降低设备的功耗&#xff0c;延长电池寿命。这篇文章将深入探讨如何在 Unity 中优化游戏的内存管理与帧率&#xff0c;通过多方…...

C++游戏开发详解

C 是一种广泛使用的编程语言&#xff0c;尤其在游戏开发领域有着不可替代的地位。它提供了对底层硬件的直接访问能力&#xff0c;允许开发者优化性能&#xff0c;这对于追求高帧率和低延迟的游戏来说至关重要。本文将详细介绍使用 C 进行游戏开发的基础知识和技术要点&#xff…...

三、大模型(LLMs)微调面

本文精心汇总了多家顶尖互联网公司在大模型基础知识考核中的核心考点&#xff0c;并针对这些考点提供了详尽的解答。并提供电子版本&#xff0c;见于文末百度云盘链接中&#xff0c;供读者查阅。 一、大模型微调 • 1 如果想要在某个模型基础上做全参数微调&#xff0c;究竟需要…...

Flutter升级与降级

升级 版本升级 // 升级到指定版本flutter upgrade 版本号// 升级到最新版本flutter upgrade 降级 1.需要先确定想要降级的版本号。 2.切换到系统安装Flutter的目录 3.在https://github.com/flutter/flutter&#xff0c;找到要回退的版本号对应的commit序号&#xff08;具…...

分布式并发场景的核心问题与解决方案

文章目录 分布式并发场景的核心问题与解决方案一、核心问题分析1. 分布式事务问题2. 数据一致性问题3. 并发控制问题4. 分布式锁失效问题 二、解决方案1. 分布式事务解决方案1.1 可靠消息最终一致性方案1.2 TCC方案实现 2. 缓存一致性解决方案2.1 延迟双删策略2.2 Canal方案 3.…...

D - Many Segments 2(ABC377)

题意&#xff1a;给定n和m&#xff0c;给定n个区间li&#xff0c;ri&#xff0c;求出满足区间lr不完全包含区间liri的个数 分析&#xff1a;用优先队列对区间r进行排序&#xff0c;i表示左区间&#xff0c;每次找到右区间加入即可。 代码&#xff1a; #include<bits/stdc…...

数组指针和指针数组的区别

数组指针和指针数组的区别 根据我个人的理解如下&#xff1a; 数组指针&#xff1a;指向数组的指针。着重点在于最后的指针两个字。 指针数组&#xff1a; 所有元素都是指针的数组。着重点在于最后的数组两个字。 另外来看助手的回答: Kimi: 1. **数组指针&#xff08;Ar…...

【VUE点击父组件按钮,跳转到子组件】

要实现在Vue中&#xff0c;父组件通过点击按钮进入子组件的 <el-dialog> 弹窗&#xff0c;并在弹窗中嵌套 <el-table> 表格&#xff0c;可以按照以下步骤进行编写代码&#xff1a; 在父组件中&#xff0c;定义一个数据属性用于控制子组件弹窗的显示与隐藏。 data…...

Java列表排序:方法与实践

在Java编程中&#xff0c;列表排序是一个常见且重要的任务。本文将介绍Java中对列表进行排序的几种方法&#xff0c;包括使用Collections.sort()、List.sort()以及自定义排序规则。 1. 使用Collections.sort() Collections.sort()是Java提供的一个静态方法&#xff0c;用于对…...

哈希及其封装实现unordermap和set

哈希 直接定址法 哈希和之前的红黑树的区别就是&#xff0c;它是通过映射关系来找到目标的&#xff0c;可以把它想象成之前排序的计数排序&#xff0c;那其实就是哈希的一种方法&#xff0c;叫做直接定址法。 对于比较集中的数据&#xff0c;它只需要开一段区间&#xff0c;…...

在 AMD GPU 上构建解码器 Transformer 模型

Building a decoder transformer model on AMD GPU(s) — ROCm Blogs 2024年3月12日 作者 Phillip Dang. 在这篇博客中&#xff0c;我们展示了如何使用 PyTorch 2.0 和 ROCm 在单个节点上的单个和多个 AMD GPU 上运行Andrej Karpathy’s beautiful PyTorch re-implementation …...

Canvas简历编辑器-选中绘制与拖拽多选交互设计

Canvas简历编辑器-选中绘制与拖拽多选交互设计 在之前我们聊了聊如何基于Canvas与基本事件组合实现了轻量级DOM&#xff0c;并且在此基础上实现了如何进行管理事件以及多层级渲染的能力设计。那么此时我们就依然在轻量级DOM的基础上&#xff0c;关注于实现选中绘制与拖拽多选交…...

简单工厂(Simple Factory)

简单工厂&#xff08;Simple Factory&#xff09; 在创建一个对象时不向客户暴露内部细节&#xff0c;并提供一个创建对象的通用接口。 说明&#xff1a; 简单工厂把实例化的操作单独放到一个类中&#xff0c;这个类就成为简单工厂类&#xff0c;让简单工厂类来决定应该用哪…...

ffmpeg拉流分段存储到文件-笔记

通过ffmpeg可以从rtsp网络流拉取数据并存储到本地文件里&#xff0c;如下命令。做个笔记 ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.168:6880/live -c copy -f segment -segment_time 60 stream_piece_%d.mp4这条 ffmpeg 命令的作用是从一个 RTSP 流中捕获视频&#xff…...

Java 实习工资大概是多少?——解读影响薪资的因素

文章目录 1. 城市因素&#xff1a;一线、二线的差距2. 公司类型&#xff1a;互联网公司、外企和传统企业的差别3. 个人能力&#xff1a;经验、技术栈的重要性4. 其他影响因素&#xff1a;学历和实习时间总结推荐阅读文章 Java 开发作为广泛应用的职业方向&#xff0c;实习工资的…...

【Linux】万字详解:Linux文件系统与软硬链接

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 &#x1f680; 前言 一&#xff1a; &#x1f525; 磁盘的物理结构二&#xff1a; &#x1f525; 磁盘的存储结构 三&#xff1a; &#x1f525; 磁盘的逻辑结构 四&#xff1a; &#…...

spacenavd

介绍spacenavd开源项目&#xff0c;主要是因为在斯坦福大学的UMI项目中使用了该项目。在斯坦福大学的 UMI&#xff08;Universal Manipulation Interface&#xff09;项目中&#xff0c;Spacenavd 主要用于处理 3D Space Mouse&#xff08;空间鼠标&#xff09;的输入&#xf…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...