从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) { }
总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/58303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重写(外壳不变)

重写&#xff1a;是子类对父类非静态、非private修饰、非final修饰、非构造方法等的实现过程进行重新编写返回值和形参都不能改变。 重写的好处&#xff1a;子类可以根据需要&#xff0c;定义专属于自己的行为。&#xff08;子类能够根据需要实现父类的方法&#xff09; 方法…

大数据日志处理框架ELK方案

介绍应用场景大数据ELK日志框架安装部署 一&#xff0c;介绍 大数据日志处理框架ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;是一套完整的日志集中处理方案&#xff0c;以下是对其的详细介绍&#xff1a; 一、Elasticsearch&#xff08;ES&#xff09; 基本…

Golang | Leetcode Golang题解之第515题在每个树行中找最大值

题目&#xff1a; 题解&#xff1a; func largestValues(root *TreeNode) (ans []int) {if root nil {return}q : []*TreeNode{root}for len(q) > 0 {maxVal : math.MinInt32tmp : qq nilfor _, node : range tmp {maxVal max(maxVal, node.Val)if node.Left ! nil {q …

怎么理解ES6 Proxy

Proxy 可以理解成&#xff0c;在目标对象之前架设一层 “拦截”&#xff0c;外界对该对象的访问&#xff0c;都必须先通过这层拦截&#xff0c;因此提供了一种机制&#xff0c;可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理&#xff0c;用在这里表示由它来 “代理…

前端知识串联笔记(更新中...)

1.MVVM MVVM 是指 Model - View - ViewModel&#xff0c;Model 是数据与业务逻辑&#xff0c;View 是视图&#xff0c;ViewModel 用于连接 View 和 Model Model ---> View&#xff1a;将数据转化成所看到的页面&#xff0c;实现的方式&#xff1a;Data Bindings -- 数据绑定…

.NET Core WebApi第6讲:WebApi的前端怎么派人去拿数据?(区别MVC)

一、前端界面小基础 head&#xff1a;引入CSS, 引入JS是写在head里面。 body&#xff1a;眼睛肉眼能看到的用户展示的界面是写在body里面。 二、前端怎么派人去拿数据&#xff1f; 1、MVC&#xff1a;前后端不分离&#xff0c;MVC相比WebApi只是多了一个views的文件夹 &am…

(蓝桥杯C/C++)—— 编程基础

文章目录 一、C基础格式 1.打印hello, world 2.基本数据类型 二、string 1.string简介 2.string的声明和初始化 3.string其他基本操作 (1)获取字符串长度 (2) 拼接字符串( 或 append) (3&#xff09;字符串查找&#xff08;find&#xff09; (4)字符串替换 (5)提取子字符串…

Spring boot 配置文件的加载顺序

Spring Boot 在启动时会扫描以下位置的 application.properties 或者 application.yml 文件作为全局配置文件&#xff1a; –file:./config/–file:./–classpath:/config/–classpath:/以下是按照优先级从高到低的顺序&#xff0c;如下所示&#xff1a; Spring Boot 会全部扫…

分类预测|基于GWO灰狼优化K近邻KNN的数据分类预测Matlab程序 多特征输入多类别输出GWO-KNN

文章目录 一、基本原理原理流程总结 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 灰狼优化&#xff08;GWO&#xff0c;Grey Wolf Optimization&#xff09;是一种基于灰狼社会行为的优化算法&#xff0c;常用于解决各种优化问题。将GWO应用于K近邻&#xff0…

『完整代码』宠物召唤

创建脚本并编写&#xff1a;PetFollowTarget.cs using UnityEngine; public class PetFollowTarget : MonoBehaviour{Transform target;float speed 2f;Animator animator;void Start(){target GameObject.Find("PlayerNormal/PetsSmallPos").gameObject.transform…

Redis 基础 问题

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 基础 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 基础 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis & 基础…

C++ 魔法三钥:解锁高效编程的封装、继承与多态

快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 目录 &#x1f4af;前言 &#x1f4af;封装 1.封装概念 2.封装格式 3.封装的原理 4.封装的作用 &#x1f4af;继承 1.继承的概念 2.继承格式 3.继承的…

情感咨询小程序的市场需求大吗?

情感咨询小程序的市场需求较大&#xff0c;主要体现在以下几个方面&#xff1a; 情感问题普遍存在5&#xff1a; 恋爱关系困扰&#xff1a;在恋爱过程中&#xff0c;人们经常会遇到诸如沟通不畅、争吵频繁、信任危机等问题。例如&#xff0c;年轻人在恋爱初期可能会因为不了解…

【现代C++】常量求值

现代C&#xff08;特别是C11及以后的版本&#xff09;增强了对编译时常量求值的支持&#xff0c;包括constexpr函数、constinit和consteval关键字。这些特性允许在编译时进行更多的计算&#xff0c;有助于优化运行时性能并确保编译时的数据不变性。 1. constexpr - 编译时常量…

震惊!总环On Hold之后,这些期刊也正在被调查!涉及Nature旗下、WR、JCLP....

On Hold期刊 总环被Oh Hold应该是学术圈最近最热的新闻了。相关的调查团队5GH 也发布了相关的推送报道此事&#xff1a; 在该推送的留言区&#xff0c;该团队也透露了一些后续的调查进展&#xff0c;涉及了Nature旗下期刊以及多个中科院一区TOP。评论中大家对于期刊的热议度很高…

Kmeans聚类算法简述

Kmeans聚类算法 1、概述 是一种无监督学习算法&#xff0c;根据样本之间的相似性将样本划分到不同的类别中&#xff0c;不同的相似度计算方式&#xff0c;会得到不同的聚类结果&#xff0c;常用的相似度计算方式有欧式距离。 目的是在没有先验条件知识的情况下&#xff0c;自…

算法设计与分析:大整数的加减乘除运算

第1关&#xff1a;大整数的加减乘除运算 任务描述 本关任务&#xff1a;掌握大整数的基本思想&#xff0c;并运用大整数的基本运算计算出常规整数n的阶乘&#xff0c;然后统计大整数n!中数字0的个数。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.大整数的…

医学影像学基础:理解CT、MRI、X射线和超声等医学影像设备的基本工作原理和成像技术

目录 医学影像学基础 1. X射线成像 2. 计算机断层扫描&#xff08;CT&#xff09; 3. 磁共振成像&#xff08;MRI&#xff09; 4. 超声成像 综合对比 1、成像原理对比 2、安全性对比 3、应用领域对比 4、设备特点对比 总结 医学影像学基础 在医学影像学中&#xff0…

super和this

相同点&#xff1a; 1.都是Java中的关键字 2.都只可以在非静态方法中使用 3.在构造方法中使用必须是第一条语句并且二者不可以同时存在不同点&#xff1a; 1.this是当前对象的引用&#xff0c;super是子类对象从父类继承下来部分成员的引用 2.在非静态成员方法中&#xff0c;…

CSS、Less、Scss

CSS、Less和SCSS都是用于描述网页外观的样式表语言&#xff0c;但它们各自具有不同的特点和功能。以下是对这三者的详细阐述及区别对比&#xff1a; 详细阐述 CSS&#xff08;Cascading Style Sheets&#xff09; 定义&#xff1a;CSS是一种用来表现HTML或XML等文件样式的计算机…