当前位置: 首页 > 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…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...