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

Java 9 到 Java 21 新特性全解析:从语法简化到API增强

一、新特性的概述

纵观Java这几年的版本变化,在Java被收入Oracle之后,Java以小步快跑的迭代方式,在功能更新上迈出了更加轻快的步伐。基于时间发布的版本,可以让Java研发团队及时获得开发人员的反馈,因此可以看到最近的Java版本,有很多语法层面简化的特性。同时,Java在支持容器化场景,提供低延迟的GC方面(ZGC等)也取得了巨大的进步。

注意一个新特性的出现通常会经过以下阶段:

  1. 孵化器(Incubator)阶段:这是新特性最早的开发和试验阶段,此时新特性只能作为一个单独的模块或库出现,而不会包含在Java SE中。在这个阶段,特性的设计可能会有些不稳定,而且会经常调整和变更。

  2. 预览(Preview)阶段:在经过了孵化器阶段的验证和修改后,新特性进入了预览阶段,这是一种在Java SE内部实现的,开发人员可以使用并对其提供反馈的渠道。此时特性可能被包含在Java SE版本中,但是它默认是未开启的,需要通过特定的命令行参数或其他方式进行启用。

  3. 正式版(GA)阶段:在经过了预览阶段的反复测试和修复后,新特性最终会在Java SE的稳定版本中发布。此时,特性被默认开启,成为Java SE的一部分,并可以在各个Java应用程序中使用。

需要注意的是,上述阶段并非一成不变,并不是所有JEP(Java Enhancement Proposal:Java增强方案)都需要经过孵化器阶段和预览阶段,这取决于特定的提案和规划。但是,Java SE领导小组通常会遵循这些阶段的流程,以确保新特性可以经过充分的评估和测试,以便能够稳定和可靠地使用在Java应用程序中。

在以下的内容中,我们对Java9到Java21新特性做一个简单的概述。

1.Java9新特性

Java9经过4次推迟,历经曲折的Java9最终在2017年9月21日发布,提供了超过150项新功能特性。

  • JEP 261: Module System

    • JDK 9 开始引入的一种全新的模块化编程方式。JPMS 的目的是为了更好地支持大型应用程序的开发和维护,同时也可以使 Java 程序在更为动态、可移植和安全的环境下运行。

  • JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)

    • 一种交互式的 Java Shell,可以在命令行上快速地进行 Java 代码的编写、验证和执行,从而提高开发者的生产力。

  • JEP 213: Milling Project Coin(细化工程改进,该计划旨在引入小型语言特性来提高代码的简洁性和可读性)

    • 在Java 9中,@SafeVarargs注解可以用于一个私有实例方法上。在Java 7和Java 8中,@SafeVarargs注解只能用于静态方法、final实例方法和构造函数。

    • 在Java 9中,可以将效果等同于final变量作为try-with-resources语句块中的资源来使用。在Java 7/8中,try-with-resources语句块中的资源必须是显式的final或事实上的final(即变量在初始化后未被修改),否则编译器会报错。这个限制限制了Java程序员使用try-with-resources语句块的能力,特别是在涉及lambda表达式、匿名类或其他读取外部变量的代码段时。

    • Java 9允许在匿名类实例化时使用钻石操作符(<>)来简化代码,但参数类型必须是具体的、可推导的类型。

    • 从Java9开始,不能使用一个单一的“_”作为标识符了。

    • 从Java9开始,接口中支持定义私有方法。

  • JEP 224: HTML5 Javadoc

    • 从Java9开始,javadoc开始支持HTML5的语法。

  • JEP 254: Compact Strings

    • 一种新的字符串表示方式,称为紧凑型字符串,以提高Java应用程序的性能和内存利用率。通过String源码得知:char[] 变成了 byte[]。

  • JEP 269: Convenience Factory Methods for Collections

    • 更加方便的创建只读集合:List.of("abc", "def", "xyz");

  • JEP 269:对Stream API进行了增强

    • 其中最显著的是引入了四个新的方法,分别是 takeWhile(), dropWhile(), ofNullable()iterate()

  • JEP 110:一个新的HTTP客户端API,名为HttpClient,它是一种基于异步和事件驱动的方式,更加高效和灵活的HTTP客户端。

2.Java10新特性

2018年3月21日,Oracle官方宣布JAVA10正式发布。JAVA10一共定义了109个新特性,其中包含JEP,对开发人员来说,真正的新特性也就一个,还有一些新的API和JVM规范以及JAVA语言规范上的改动。

- JEP 286:局部变量类型推断
- JEP 296:将 JDK 森林合并到单个存储库中
- JEP 304:垃圾收集器接口
- JEP 307:G1 的并行完整 GC
- JEP 310:应用程序类数据共享
- JEP 312:线程局部握手
- JEP 313:删除本机头生成工具 (javah)
- JEP 314:附加 Unicode 语言标签扩展
- JEP 316:替代内存设备上的堆分配
- JEP 317:基于 Java 的实验性 JIT 编译器
- JEP 319:根证书
- JEP 322:基于时间的发布版本控制

3.Java11新特性

2018年9月26日,Oracle官方发布JAVA11。这是JAVA大版本周期变化后的第一个长期支持版本,官方支持到2026年。

  • JEP 181:基于 Nest 的访问控制

  • JEP 309:动态类文件常量

  • JEP 315:改进 Aarch64 内部函数

  • JEP 318:Epsilon:无操作垃圾收集器

  • JEP 320:删除 Java EE 和 CORBA 模块

  • JEP 321:HTTP 客户端(标准)

  • JEP 323:本地变量语法LAMBDA参数

  • JEP 324:与Curve25519密钥协商和Curve448

  • JEP 327:Unicode的10

  • JEP 328:飞行记录器

  • JEP 329:ChaCha20和Poly1305加密算法

  • JEP 330:启动单文件源代码程序

  • JEP 331:低开销堆纹

  • JEP 332:传输层安全性 (TLS) 1.3

  • JEP 333:ZGC:可扩展的低延迟垃圾收集器(实验性)

  • JEP 335:弃用 Nashorn JavaScript 引擎

  • JEP 336:弃用 Pack200 工具和 API

4.Java12新特性

2019年3月19日,java12正式发布。

  • JEP 189:Shenandoah:一个低暂停时间的垃圾收集器(实验性)

  • JEP 230:微基准套件

  • JEP 325:switch表达式(预览)

  • JEP 334:JVM 常量 API

  • JEP 340:一个 AArch64 端口

  • JEP 341:默认 CDS 档案

  • JEP 344:G1 支持可中断的 Mixed GC

  • JEP 346:及时从 G1 返回未使用的已提交内存

5.Java13新特性

  • JEP 350:动态 CDS 档案

  • JEP 351:ZGC:取消提交未使用的内存

  • JEP 353:重新实现旧的 Socket API

  • JEP 354:开关表达式(预览)

  • JEP 355:文本块(预览)

6.Java14新特性

  • JEP 305:instanceof 的模式匹配(预览)

  • JEP 343:包装工具(孵化器)

  • JEP 345:G1 的 NUMA 感知内存分配

  • JEP 349:JFR 事件流

  • JEP 352:非易失性映射字节缓冲区

  • JEP 358:有用的空指针异常

  • JEP 359:记录(预览)

  • JEP 361: switch表达式(标准)

  • JEP 362:弃用 Solaris 和 SPARC 端口

  • JEP 363:删除并发标记清除 (CMS) 垃圾收集器

  • JEP 364:macOS 上的 ZGC

  • JEP 365:Windows 上的 ZGC

  • JEP 366:弃用 ParallelScavenge + SerialOld GC 组合

  • JEP 367:删除 Pack200 工具和 API

  • JEP 368:文本块(第二次预览)

  • JEP 370:外部内存访问 API(孵化器)

7.Java15新特性

  • JEP 339:爱德华兹曲线数字签名算法 (EdDSA)

  • JEP 360:密封类(预览)

  • JEP 371:隐藏类

  • JEP 372:删除 Nashorn JavaScript 引擎

  • JEP 373:重新实现旧版 DatagramSocket API

  • JEP 374:禁用和弃用偏向锁定

  • JEP 375:instanceof 的模式匹配(第二次预览,无改动)

  • JEP 377:ZGC:可扩展的低延迟垃圾收集器(确定正式版)

  • JEP 378:文本块(确定正式版)

  • JEP 379:Shenandoah:一个低暂停时间的垃圾收集器(确定正式版)

  • JEP 381:删除 Solaris 和 SPARC 端口

  • JEP 383:外内存访问API(第二孵化器)

  • JEP 384:记录(第二次预览)

  • JEP 385:弃用 RMI 激活以进行删除

8.Java16新特性

- JEP 338:Vector API(孵化器)
- JEP 347:启用 C++14 语言功能
- JEP 357:从 Mercurial 迁移到 Git
- JEP 369:迁移到 GitHub
- JEP 376:ZGC:并发线程栈处理
- JEP 380:Unix 域套接字通道
- JEP 386:Alpine Linux 端口
- JEP 387:弹性元空间
- JEP 388:Windows/AArch64 端口
- JEP 389:外链 API(孵化器)
- JEP 390:基于值的类的警告
- JEP 392:打包工具
- JEP 393:外内存访问API(第三孵化器)
- JEP 394:instanceof 的模式匹配
- JEP 395:记录
- JEP 396:默认情况下强封装JDK内部
- JEP 397:密封类(第二次预览)

9.Java17新特性

2021年9月14日,java17正式发布(LTS)。长期支持版,支持到2029年。Oracle 宣布,从JDK17开始,后面的JDK都全部免费提供。

  • JEP 306:恢复始终严格的浮点语义

  • JEP 356:增强型伪随机数发生器

  • JEP 382:新的 macOS 渲染管线

  • JEP 391:macOS/AArch64 端口

  • JEP 398:弃用 Applet API 以进行删除

  • JEP 403:强封装JDK内部

  • JEP 406:switch模式匹配(预览)

  • JEP 407:删除 RMI 激活

  • JEP 409:密封类(正式确定)

  • JEP 410:删除实验性 AOT 和 JIT 编译器

  • JEP 411:弃用安全管理器以进行删除

  • JEP 412:外部函数和内存 API(孵化器)

  • JEP 414:Vector API(第二孵化器)

  • JEP 415:上下文特定的反序列化过滤器

10.Java18新特性

2022年3月22日发布。非长期支持版本。

  • JEP 400:从JDK18开始,UTF-8是Java SE API的默认字符集。

  • JEP 408:从JDK18开始,引入了jwebserver这样一个简单的WEB服务器,它是一个命令工具。

  • JEP 416:使用方法句柄重新实现核心反射

  • JEP 418:互联网地址解析SPI

  • JEP 413:Java API文档中的代码段(javadoc注释中使用<pre></pre>括起来的代码段会原模原样的生成到帮助文档中)

  • JEP 417:Vector API(第三孵化器)

  • JEP 419:Foreign Function & Memory API(第二孵化器)

  • JEP 420:switch 的模式匹配(第二次预览)

  • JEP 421:Object中的finalize()方法被移除

11.Java19新特性

2022年9月20日发布。非长期支持的版本。直到 2023 年 3 月它将被 JDK 20 取代。

  • JEP 425:虚拟线程(预览版)

    • 一种新的线程模型,即虚拟线程;"虚拟线程" 指的是一种轻量级线程,可以通过 JVM 进行管理和调度,而不需要操作系统进行支持

  • JEP 428:结构化并发(孵化器)

    • 一组新的API和规范,用于优化并简化Java程序的并发编程

  • JEP 405:Record模式 (预览版)

  • JEP 427:switch语句中的模式匹配(第三次预览版)

    • "switch语句中的模式匹配"表示该特性是针对 switch 语句的改进,可以使用模式匹配的方式处理 switch 语句中的分支

  • JEP 424:外部函数和内存API(预览版)

    • “外部函数”指的是在Java程序中调用非Java语言编写的函数,比如C/C++函数

    • “内存API”指的是在Java程序中直接操作内存的API

  • JEP 426:向量API(第四版孵化器)

    • 一组专用于向量化处理的API,允许在Java程序中轻松高效地执行向量化计算

12.Java20新特性

2023年3月21日发布。非长期支持版本。直到 2023 年 9月它将被 JDK 21 取代。

  • JEP 432: Record模式(第二次预览版)

  • JEP 433: switch的模式匹配 (第四次预览版)

  • JEP 434: 外部函数和内存API(第二次预览版)

  • JEP 438: 向量API (第五版孵化器)

  • JEP 429: Scoped Values (Incubator)

  • JEP 436: 虚拟线程(第二次预览版)

  • JEP 437: 结构化并发(第二版孵化器)

13.Java21新特性

2023年9月19日发布。长期支持版本。

  • JEP 440:Record模式(正式确定)

  • JEP 441:switch的模式匹配(正式确定)

  • JEP 430:String Templates (Preview)

  • JEP 443:Unnamed Patterns and Variables (Preview)

  • JEP 445:Unnamed Classes and Instance Main Methods (Preview)

  • JEP 444:Virtual Threads(正式确定)

  • JEP 431:Sequenced Collections(正式确定)

  • JEP 452:Key Encapsulation Mechanism API

  • JEP 442:Foreign Function & Memory API (Third Preview)

  • JEP 453:Structured Concurrency (Preview)

  • JEP 446:Scoped Values (Preview)

  • JEP 448:Vector API (Sixth Incubator)

  • JEP 439:Generational ZGC

  • JEP 451:Prepare to Disallow the Dynamic Loading of Agents

二、新语法方面的变化

1.jShell命令

jShell命令是Java9引进的新特性,像Python和Scala之类的语言早就有交互式编程环境REPL (read-evaluate-print-loop),以交互式的方式对语句和表达式进行求值。

开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java 版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。

我们打开DOS命令窗口,然后输入jshell,就能进入交互式编程环境REPL,如下图所示

通过jShell命令,我们能够定义一些变量,并执行相关的运算操作,如下图所示:

通过jShell命令,我们能够定义方法,并执行调用方法的操作,如下图所示:

想要查看JShell提供的所有指令,则直接输入“/help”即可,如下图所示:

想要查看书写的所有代码,则直接输入“/list”指令即可,如下图所示:

想要查看定义的所有变量,则直接输入“/vars”指令即可,如下图所示:

想要查看定义的所有方法,则直接输入“/methods”指令即可,如下图所示:

2.try-with-resources

众所周知,所有被打开的系统资源,比如流、文件、Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故。 在Java7以前,我们想要关闭资源就必须的finally代码块中完成。

【示例】Java7之前资源的关闭的方式

public void copyFile1(File srcFile, File destFile) {FileInputStream fis = null;FileOutputStream fos = null;try {// 实例化IO流(输入流和输出流)fis = new FileInputStream(srcFile);fos = new FileOutputStream(destFile);// 拷贝文件(存储和读取)int len = 0;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 关闭资源if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}
}

Java7及以后关闭资源的正确姿势:try-with-resource,该语法格式为:

try(/*实例化需要关闭资源的对象或引用需要关闭资源的对象*/){// 书写可能出现异常的代码
} catch(Exception e) {// 处理异常
}

使用try-with-resource来自动关闭资源,则需要关闭资源的对象对应的类就必须实现java.lang.AutoCloseable接口,该接口中提供了一个close()的抽象方法,而自动关闭资源默认调用的就是实现于java.lang.AutoCloseable接口中的close()方法。 因为FileInputStream类和FileOutputStream类都属于java.lang.AutoCloseable接口的实现类,因此此处文件拷贝的操作就可以使用try-with-resource来自动关闭资源。

【示例】Java7之后资源的关闭的方式

public void copyFile(File srcFile, File destFile) {// 实例化IO流(输入流和输出流)try (FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(destFile)) {// 拷贝文件(存储和读取)int len = 0;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}

通过try-with-resource来关闭放资源,即使资源很多,代码也可以写的很简洁,如果用Java7之前的方式去关闭资源,那么资源越多,用finally关闭资源时嵌套也就越多。 在Java9之后,为了避免在try后面的小括号中去实例化很多需要关闭资源的对象(复杂),则就可以把需要关闭资源的多个对象在try之前实例化,然后在try后面的小括号中引用需要关闭资源的对象即可,从而提高了代码的可读性。

【示例】Java9之后的使用方式

public void copyFile(File srcFile, File destFile) throws FileNotFoundException {// 实例化IO流(输入流和输出流)FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(destFile);// 拷贝文件(存储和读取)try (fis; fos) {int len = 0;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}
}

在以上代码中,表达式中引用了fis和fos,那么在fis和fos就自动变为常量啦,也就意味着在try代码块中不能修改fis和fos的指向,从而保证打开的资源肯定能够关闭。

3.局部变量类型判断

在Java10中,新增了局部变量类型判断。在方法体或代码块中,对于可以在编译期确定的类型,可以使用var来定义。这个特性并不意味着java是弱类型的语言,仅是提供了更简洁的书写方式。对于编译期无法确定的类型,依然要写清楚类型。
【示例】局部变量类型判断案例

* Description:
*          Java10的新特性:局部变量类型判断
/*** ClassName: NewFun02* Description:*          Java10的新特性:局部变量类型判断*/
public class NewFun02 {String name = "zhangsan";// 报错//var myName = "lisi";public static void doSome(int i){}// 报错/*public static void doOther(var i){}*/public static void main(String[] args) {/*int i = 100;double d = 3.14;boolean flag = false;*/// 使用Java10的新特性:局部变量类型推断var i = 100;var d = 3.14;var flag = false;System.out.println(i);System.out.println(d);System.out.println(flag);}
}

报错:

运行结果:

4.instanceof的模式匹配

在JDK14中新增instanceof模式匹配增强(预览),在JDK16中转正。通过instanceof模式匹配增强,我们就可以直接在模式匹配的括号内声明对应类型的局部变量。
【示例】执行向下转型的操作

父类Animal:

/*** ClassName: Animal* Description:*/
public class Animal {
}

子类Cat:

/*** ClassName: Cat* Description:*/
public class Cat extends Animal{// 这个方法是子类特有的。父类没有。public void catchMouse(){System.out.println("猫抓老鼠");}
}

测试类:

/*** ClassName: NewFun03* Description:*      Java14的新特性:instanceof的模式匹配。*      Java16发布的正式版本。**      作业:自己尝试重写一下某个类的equals方法,请使用新特性:instanceof的模式匹配。*/
public class NewFun03 {public static void main(String[] args) {// 以前Animal a = new Cat();if(a instanceof Cat) {Cat cat = (Cat) a;cat.catchMouse();}// 使用instanceof模式匹配之后if(a instanceof Cat c){c.catchMouse();}}
}

运行结果:

【示例】重写equals(),判断成员变量是否相等

public class Tiger {String name;int age;/*** 以前的代码实现方式*//*@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null) return false;// 如果obj属于Tiger类型,则就执行向下转型的操作if (obj instanceof Tiger) {// 执行向下转型的操作,恢复对象的实际类型Tiger tiger = (Tiger) obj;// 如果成员变量都相等,则返回true,否则返回falsereturn age == tiger.age && Objects.equals(name, tiger.name);}// 如果obj不属于Tiger类型,则返回false即可return false;}*//*** 使用instanceof模式匹配增强的实现方式*/@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null) return false;// 如果obj属于Tiger类型并且成员变量值都相等,那么返回trueif (obj instanceof Tiger tiger) {return age == tiger.age && Objects.equals(name, tiger.name);}// 如果obj不属于Tiger类型,则返回false即可return false;}
}

5.switch表达式

目前switch表达式的问题:

  1. 匹配自上而下,若无break,后面的case语句都会执行

  2. 不同的case语句定义的变量名不能相同

  3. 不能在一个case后面写多个值

  4. 整个switch不能作为表达式的返回值

在Java12中对switch表达式做了增强(预览),能够使用更加简洁的代码来解决这些问题。

【示例】switch表达式使用的案例

在Java13中,增加关键字yield关键字(预览), 用于在switch表达式中返回结果。到Java14版本中,Java12和Java13中关于switch的新特性都确定为正式版本。

【示例】switch表达式中的yield关键字

/*** ClassName: NewFun04* Description:*      Java12新特性:switch增强。*      Java13中也对switch进行了再次的增强。*/
public class NewFun04 {public static void main(String[] args) {// 不使用增强,switch怎么写?int month = 10;switch (month) {//case 3, 4, 5:case 3: case 4: case 5:int i = 100;System.out.println("春季");break;case 6: case 7: case 8://int i = 200;System.out.println("夏季");break;case 9: case 10: case 11:System.out.println("秋季");//break;case 12: case 1: case 2:System.out.println("冬季");break;}// 使用java12增强后的switchswitch (month) {case 3,4,5 -> {System.out.println("春季");int i = 100;}case 6,7,8 -> {System.out.println("夏季");int i = 200;}case 9,10,11 -> System.out.println("秋季");case 12,1,2 -> System.out.println("冬季");}// 在java12增强switch之后,switch语句执行结束之后可以有返回值。//month = 100;String season = switch (month) {case 3,4,5 -> "春季";case 6,7,8 -> "夏季";case 9,10,11 -> "秋季";case 12,1,2 -> "冬季";default -> throw new RuntimeException("月份不对!");};System.out.println(season);// 在java13中对switch又进行了增强。month = 3;String season2 = switch (month) {case 3: case 4: case 5:yield "春季";case 6: case 7: case 8:yield "夏季";case 9: case 10: case 11:yield "秋季";case 12: case 1: case 2:yield "冬季";default: throw new RuntimeException("月份不对!");};System.out.println(season2);}
}

运行结果:

6.文本块

在Java语言中,通常需要使用String类型表达HTML,XML,SQL或JSON等格式的字符串,在进行字符串赋值时需要进行转义和连接操作,然后才能编译该代码,这种表达方式难以阅读并且难以维护。

在Java12版本中,新增了文本块(预览)。文本块就是指多行字符串,例如一段格式化后的xml、json等。而有了文本块以后,用户不需要转义,Java能自动搞定。因此,文本块将提高Java程序的可读性和可写性。

/*** ClassName: NewFun05* Description:*          Java12的新特性:文本块*/
public class NewFun05 {public static void main(String[] args) {// 需求:输出一段HTML代码到控制台。并且要求展示的格式如下:/*<html><head><title>first page</title></head><body><h1>my first html page!</h1></body></html>*/String htmlCode = "<html>\n" +"    <head>\n" +"        <title>first page</title>\n" +"    </head>\n" +"    <body>\n" +"        <h1>my first html page!</h1>\n" +"    </body>\n" +"</html>";System.out.println(htmlCode);// 使用文本块String htmlCode2 = """<html><head><title>first page</title>\</head><body><h1>my first html pag\s\s\s\s\s\se!</h1></body></html>""" ;System.out.println(htmlCode2);}
}

运行结果:

在Java14版本中,针对文本块又新增两个特性(阅览)。1)在一行的结尾增加“\”可以取消改行的换行符;2)可以通过“\s”增加空格。

【示例】演示文本块新增特性

// 取消换行(\)
String json1 = """{"username":"ande",\"age":18}""";
System.out.println(json1);
// 添加空格(\s)
String json2 = """{"username"\s:\s"ande","age"\s:\s18}""";
System.out.println(json2);

7.Record

早在2019年2月份,Java语言架构师Brian Goetz就吐槽了Java语言,他和很多程序员一样抱怨“Java太啰嗦”或有太多的“繁文缛节”,他提到:开发人员想要创建纯数据载体类,通常都必须编写大量低价值、重复的、容易出错的代码。例如:构造方法、getter/setter、equals()、hashCode()以及toString()等。 以至于很多人选择使用IDE的功能来自动生成这些代码。还有一些开发会选择使用一些第三方类库,如Lombok等来生成这些方法,从而会导致了令人吃惊的表现和糟糕的可调试性。 那么,Brian Goetz大神提到的纯数据载体到底指的是什么呢?我们举了一个简单的例子:

public final class Tiger {private final String name;private final int age;public Tiger(String name, int age) {this.name = name;this.age = age;}public String name() {return name;}public int age() {return age;}@Overridepublic boolean equals(Object obj) {if (obj == this) return true;if (obj == null || obj.getClass() != this.getClass()) return false;var that = (Tiger) obj;return Objects.equals(this.name, that.name) &&this.age == that.age;}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Tiger[" +"name=" + name + ", " +"age=" + age + ']';}
}

这里面的Tiger其实就是一个纯数据载体,Tiger类中提供了name和age两个私有常量,并且只提供了全参构造方法和常量名相同的getter方法,以及一些equals、hashCode和toString等方法。于是,BrianGoetz大神提出一种想法,他提到,Java完全可以对于这种纯数据载体通过另外一种方式表示。

在Java14版本中,新增了Record类型。Record是Java的一种新的类型,Record使数据类型变得非常简洁,一般可以帮助我们定义一些简单的用于纯数据载体的实体类。

Record类的特点:

状态声明中的每个属性,都是默认采用了private和final修饰,则属性值就不可修改

在Record类中,默认已经重写了Object类提供的equals(),hashcode(),toString()方法

在Record类中,默认提供全参的构造方法,并且提供的getter方法名和属性名保持一致。

Record类采用了final修饰,并且显示的继承于java.lang.Record类,因此就不能继承别的父类。 【示例】将以上的Tiger类转化为Record类

public record Tiger(String name, int age)  {}

在以上的Record类中,Tiger类默认采用了final修饰,并且显示的继承于java.lang.Record抽象类,因此Tiger类就不能继承于别的父类。在Tiger类中,提供了name和age两个私有常量,并且还提供了一个public修饰的全参构造方法,提供的getter方法的名字和属性名保持一致,但是并没有提供setter方法。并且,在Tiger类中还重写了Object类提供的equals(),hashcode(),toString()方法。

在Record类中,我们还可以新增静态属性、无参构造方法、成员方法和静态方法,但是创建对象时不能调用无参构造方法,而是通过全参构造方法创建对象的时候,默认就会调用Record类中的无参构造方法。

【示例】在Record类中添加的内容

public record Tiger(String name, int age)  {// 新增静态属性static double score;// 新增无参构造方法// 注意:通过全参构造方法创建对象,默认就会调用此处的无参构造方法public Tiger {System.out.println("无参构造方法");}// 新增成员方法void show() {System.out.println("show. ..");}// 新增静态方法static void method() {System.out.println("method ...");}
}

示例运行代码:

/*** ClassName: User* Description:*          这个类中的属性是final修饰的,并且只提供了属性的读取方法。没有提供属性的修改方法。*          很明显,这个类其实起到的作用就是:纯数据的载体。*/
/*public final class User {private final String name;private final int age;public User(String name, int age) {this.name = name;this.age = age;}public String name(){return name;}public int age(){return age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return age == user.age && Objects.equals(name, user.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}*/// 如果在开发中,你需要这样一个类:专门只做纯数据的载体。那么可以将这种类型定义为Record类型。
public record User(String name, int age) {// 自动带有两个实例变量,并且被final修饰,一个是name,一个是age。// 自动带有toString方法// 自动带有hashCode + equals方法// 自动带有 name() 方法// 自动带有 age() 方法// 自动带有全参数的构造方法// Record类型中可以添加什么?// 无参数的构造方法public User{System.out.println("Record类型的无参数构造方法");}// 静态变量static int i = 100;// 静态方法public static void m1(){System.out.println("m1....");}// 实例方法public void m2(){System.out.println("m2...");}
}// 测试类
class UserTest {public static void main(String[] args) {User user = new User("zhangsan", 20);System.out.println(user.name());System.out.println(user.age());System.out.println(user.toString());System.out.println("静态变量:" + User.i);User.m1();user.m2();}
}

运行结果:

8.密封类

Java中的密封类是一种新的类修饰符,它可以修饰类和接口,可以控制哪些类可以扩展或实现该类或接口。下面是密封类的一些主要用途:

  1. 维护类层次结构的封闭性

密封类的一个主要用途是确保类层次结构的封闭性。这意味着,如果您想保护一组类,而不希望其他类继承或实现它们,可以使用密封类来实现这一目标。这对于确保代码的安全性和稳定性非常有用。

  1. 预防代码的意外扩展

密封类可以防止其他程序员意外地扩展一个类。在进行类设计时,您可能希望自己或其他程序员只能在特定的类中实现或继承指定的类。在这种情况下,您可以将类标记为“密封”,强制限制其他程序员可以实现或继承的类的范围。

  1. 增强代码的可读性和可维护性

密封类可以增强代码的可读性和可维护性。由于密封类明确规定了哪些类可以扩展或实现它,因此其他开发人员可以更清晰地看到代码的结构并理解它们的关系。这使得代码更易于维护和修改。 总之,密封类是一种灵活而有用的类修饰符,可以帮助您维护类的封闭性、预防代码的意外扩展、增强代码的可读性和可维护性。

在Java15版本中,新增了密封类和密封接口(预览)。 使用sealed关键字修饰的类,我们就称之为密封类密封类必须是一个父类,我们可以使用permits关键字来指定哪些子类可以继承于密封类,并且密封类的子类必须使用sealed、final或non-sealed来修饰。


/*** ClassName: SealedTest* Description:*      在Java15版本中,新增了密封类和密封接口*/
public class SealedTest {
}// 现在定义的这个T类是可以被所有子类继承的。没有任何限制。
class T {}
class T1 extends T{}
class T2 extends T{}
class T3 extends T{}
class T4 extends T{}// 需求:定义一个Person类,只允许 Teacher、Student、Worker这三个类继承。
// 怎么定义密封类:在class关键字前面添加 sealed 关键字。
// 添加了 sealed 之后,该类成为密封类,必须使用 permits 关键字指定哪些子类可以继承我。
sealed class Person permits Teacher, Student, Worker {}// 当一个类继承了密封类之后,该类必须使用 final、sealed、non-sealed 这三个关键字中的一个关键字进行修饰。
// final 最终的
// sealed 密封的
// non-sealed 非密封的
final class Teacher extends Person {}
non-sealed class Student extends Person {}sealed class Worker extends Person permits OtherWorker {}
non-sealed class OtherWorker extends Worker{}
//class T5 extends Person{}// 密封接口
// 只允许A B C三个类实现这个接口
sealed interface MyInterface permits A,B,C {}
final class A implements MyInterface{}
non-sealed class B implements MyInterface{}
sealed class C implements MyInterface permits D{}
non-sealed class D extends C {}
//class E implements MyInterface{}// Record 和 Sealed的关系。
sealed interface ProductService permits Product {}// Record类型默认被final修饰。
// Record类型可以做密封接口的实现类。
record Product(String name, double price) implements ProductService { }
//底层继承了别的类,不可以再继承类

三、API层面的变化

1.String存储结构改变

在Java8及其之前,String底层采用char类型数组来存储字符;在Java9及其以后,String底层采用byte类型的数组来存储字符。将char[]转化为byte[],其目的就是为了节约存储空间。

2.String 新增的方法

在Java11版本中,对String类新增了一些方法,新增的方法如下:

// 空格,制表符,换行等都认为是空的
boolean blank = "\t \n".isBlank();
System.out.println(blank); // 输出:trueString source = "\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000www.baidu.com\u3000\u3000\u3000\u3000\u3000";
// 去除“前后”的中文空格
System.out.println(source.strip());
// 去除“开头”的中文空格
System.out.println(source.stripLeading());
// 去除“末尾”的中文空格
System.out.println(source.stripTrailing());// 把字符串内容重复n份
String repeat = "xixi".repeat(3);
System.out.println(repeat); // 输出:xixixixixixi// 按照换行来分割字符串,返回的结果是Stream对象
Stream<String> lines = "a\nb\nc\n".lines();
System.out.println(lines.count()); // 输出:3

在Java12版本中,对String类新增了一些方法,新增的方法如下:

// 在字符串前面添加n个空格
String result2 = "Java Golang".indent(4);
System.out.println(result2);

测试代码:

/*** ClassName: NewStringTest* Description:*/
public class NewStringTest {public static void main(String[] args) {// 1. 在java9之后(包括java9在内),String启用了压缩机制,以前是char[],变成了 byte[] 数组。// 2. java11新增了 isBlank() 方法,判断某个字符串是否为空,“制表符,空格,换行符”统一都被认为是空字符串。System.out.println("\t      \n".isBlank()); // true// 3. java11新增了 strip()、stripLeading()、stripTrailing() 去除所有类型的空格。包括中文空格。// 4. java11新增了 repeat() 方法String repeat = "haha".repeat(3);System.out.println(repeat);// 5. java11新增了 lines() 方法,将字符串以换行符进行分割,生成一个流对象Stream<String> stream = "abc\ndef\nxyz\n".lines();//stream.forEach(System.out::println);System.out.println("行数:" + stream.count());// 6. java12新增了 indent() 方法String str = "hello world".indent(4);System.out.println(str);}
}

运行结果:

3.接口支持私有方法

在Java8版本中,接口中支持“公开”的静态方法和公开的默认方法;在Java9版本中,接口中还允许定义“私有”的静态方法和成员方法,但是不能定义私有的默认方法。

【示例】演示接口中的私有静态方法和成员方法

/*** 接口(JDK1.9)*/
public interface Flyable {// 私有的静态方法private static void staticMethod() {System.out.println("static method ...");}// 私有的成员方法private void method() {System.out.println("default method ...");}
}

4.标识符命名的变化

在Java8及其之前,标识符可以独立使用“_”来命名。

String _ = "hello";
System.out.println(_);

但是,在Java9中规定“_”不能独立命名标识符了,如果使用就会报错:

5.简化编译运行程序

在我们的认知里面,要运行一个Java源代码必须先编译(javac命令),再运行(java命令),

两步执行动作。而在Java 11版本中,通过一个java命令就直接搞定了。

需要执行的程序:

public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");}
}

执行java命令进行运行,如下图所示:

6.创建不可变集合

在Java9版本中,我们可以通过List、Set和Map接口提供的of(E... elements)静态方法来创建不可变集合。通过此方式创建的不可变集合,我们不但不能添加或删除元素,并且还不能修改元素。

import java.util.Arrays;
import java.util.List;
import java.util.Set;/*** ClassName: ReadOnlyCollection* Description:*          创建只读集合(不可变集合)。*          这种集合不可以添加元素/修改元素/删除元素。**/
public class ReadOnlyCollection {public static void main(String[] args) {// 创建一个不可变的集合对象List<Integer> list = List.of(1, 2, 3, 4, 5);System.out.println(list);// 以下的增删改,都是不支持的。//list.add(100);//list.remove(0);//list.set(1, 100);// 创建一个不可变的Set集合对象Set<String> set = Set.of("abc", "def", "xyz");System.out.println(set);// Arrays.asList() 这个方法也可以返回一个只读的集合List<Integer> list1 = Arrays.asList(100, 200, 300);System.out.println(list1);// 不可以//list1.add(600);// 不可以//list1.remove(0);// 可以(这个就是一个小区别 和 List.of)list1.set(0, 666);System.out.println(list1);}
}

运行结果:

7.Optional API

在Java8以前,Java程序员操作对象时,为了避免错误引用null造成的空指针异常,往往需要一系列繁杂冗余的判空操作,增加了许多重复代码,降低了代码可读性,于是Java 8引入Optional类,优雅简洁的对null值进行处理,从而避免出现空指针异常(NullPointerException)。 本质上,Optional 类是一个包含有可选值的包装类,这意味着 Optional 类中既可以含有对象也可以为null。

⑴.创建Optional对象

使用Optional类提供的of( )和ofNullable( ) 静态方法来创建包含值的Optioanal实例。

如果将null当作参数传进去of( )会抛出空指针异常如果将null当作参数传进去 ofNullable( ) 就不会抛出空指针异常。 因此当对象可能存在或者不存在,应该使用 ofNullable( )方法来创建Optional实例。

【示例】创建一个Optional实例

import java.util.Optional;/*** ClassName: OptionalAPI*/
public class OptionalAPI {public static void main(String[] args) {// Optional API是Java8引入的。(专门做空处理的。避免空指针异常的)//有一场商业表演,原计划让“刘亦菲”来表演,如果“刘亦菲”不能参加,则就换“佟丽娅”来表演//String name = "刘亦菲";/*String name = null;if(name == null) {name = "佟丽娅";}System.out.println("最终参与商业表演的演员是:" + name);*/// 以上代码采用Optional API可以代替。String name = null;// 获取 Optional 对象(将可能为空的name封装成Optional对象)Optional<String> optional = Optional.ofNullable(name);// 原理:// 如果 optional 对象中封装的数据是 null,则选择 参数 作为返回值。// 如果 optional 对象中封装的数据不是 null,则选择 封装的数据 作为返回值。String finalName = optional.orElse("佟丽娅");System.out.println("最终参与商业表演的演员是:" + finalName);}
}

运行结果:

⑵.Optional类的方法

想要获得Optional实例中包含的值,那么就可以使用以下两个方法来实现。

方法名描述
public T get()如果值不为null,则直接取出该值;如果值为null,则抛出空指针异常。
public T orElse(T other)如果值不为null,则直接取出该值;如果值为null,则取出的就是参数other的值。

开发中,我们获取Optional中存储的值,一般都是采用orElse(T other)方法来实现。

【示例】演示get()方法

// 创建一个包含“null”的Optional示例
Optional<Object> optional1 = Optional.ofNullable(null);
Object obj1 = optional1.get(); // 抛出空指针异常
// 创建一个包含“对象”的Optional示例
Optional<String> optional2 = Optional.ofNullable("hello");
String str = optional2.get();
System.out.println(str); // 输出:hello

【示例】演示orElse(T other)方法

// 创建一个包含“null”的Optional示例
Optional<Object> optional1 = Optional.ofNullable(null);
Object str1 = optional1.orElse("world");
System.out.println(str1); // 输出:world
// 创建一个包含“对象”的Optional示例
Optional<String> optional2 = Optional.ofNullable("hello");
String str2 = optional2.orElse("world");
System.out.println(str2); // 输出:hello

8.11.17.21是长期支持版本

相关文章:

Java 9 到 Java 21 新特性全解析:从语法简化到API增强

一、新特性的概述 纵观Java这几年的版本变化&#xff0c;在Java被收入Oracle之后&#xff0c;Java以小步快跑的迭代方式&#xff0c;在功能更新上迈出了更加轻快的步伐。基于时间发布的版本&#xff0c;可以让Java研发团队及时获得开发人员的反馈&#xff0c;因此可以看到最近…...

LeeCode题库第三十九题

39.组合总和 项目场景&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同…...

卫星网络仿真平台:IPLOOK赋能空天地一体化通信新生态​

卫星仿真平台 在6G技术加速演进与天地一体化网络建设的大背景下&#xff0c;卫星通信作为地面网络的重要补充&#xff0c;正成为全球通信覆盖的关键支撑。IPLOOK凭借其深厚的技术积累与创新实践&#xff0c;推出的卫星网络仿真平台​&#xff08;SCEPS&#xff09;&#xff0c…...

(十一)基于vue3+mapbox-GL实现模拟高德实时导航轨迹播放

要在 Vue 3 项目中结合 Mapbox GL 实现类似高德地图的实时导航轨迹功能,您可以按照以下步骤进行: 安装依赖: 首先,安装 mapbox-gl 和 @turf/turf 这两个必要的库: npm install mapbox-gl @turf/turf引入 Mapbox GL: 在组件中引入 mapbox-gl 并初始化地图实例: <templ…...

计算机面试项目经历描述技巧

在计算机类岗位的面试中&#xff0c;项目经历是面试官评估候选人技术能力、问题解决能力和实战经验的核心环节。以下是专业化的项目经历描述策略&#xff08;附模板框架&#xff09;&#xff1a; 一、结构化表达框架&#xff08;STAR-RT模型&#xff09; Situation&#xff08;…...

132. 分割回文串 II

简单分析 输入的参数是字符串s&#xff0c;返回值是最小的切割次数。那这个问题的典型解法应该是动态规划&#xff0c;因为我们需要找最优解&#xff0c;而每一步的选择可能会影响后面的结果&#xff0c;但可以通过子问题的最优解来构建整体最优解。 那么动态规划的状态如何定…...

【每日学点HarmonyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较

【每日学点HarmnoyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较 1、HarmonyOS 是否存在统一调整全局字体大小的方法&#xff1f; 是否存在统一调整全局字体大小的方法 可以用动态属性&#xff0c;自定义class实现At…...

九、Spring Boot:自动配置原理

深入解析 Spring Boot 自动配置原理 Spring Boot 的自动配置机制是其最核心的特性之一&#xff0c;它极大地简化了 Spring 应用的初始搭建和开发过程。通过自动配置&#xff0c;Spring Boot 能够根据项目的依赖和配置自动加载和配置 Spring 应用的各个部分。本文将深入探讨 Sp…...

(动态规划 最长重复子数组)leetcode 718

思路就是建立一个二维的dp数组&#xff0c;只要nums1[i]nums2[j]&#xff08;nums1和nums2出现重复元素就置1 并加上左上角的值) 为什么代码是nums1 i-1和nums2 i-1 答&#xff1a;因为i和j以1为初始值开始遍历的 为什么要这么做并且为什么要加dp【i-1】【j-1】&#xff1f; …...

SFP+(Enhanced Small Form-factor Pluggable)详解

1. SFP的定义 SFP&#xff08;Small Form-factor Pluggable Plus&#xff09;是SFP的增强版本&#xff0c;专为10Gbps及以上高速网络设计。它继承了SFP的小型化、热插拔特性&#xff0c;但通过优化电气接口和协议支持&#xff0c;实现了更高的传输速率&#xff08;典型为10Gbp…...

计算机毕业设计Hadoop+Spark+DeepSeek-R1大模型音乐推荐系统 音乐数据分析 音乐可视化 音乐爬虫 知识图谱 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Deepseek对ChatGPT的冲击?

从测试工程师的视角来看&#xff0c;DeepSeek对ChatGPT的冲击主要体现在**测试场景的垂直化需求与通用模型局限性之间的博弈**。以下从技术适配性、效率优化、风险控制及未来趋势四个维度展开分析&#xff1a; --- ### **一、技术适配性&#xff1a;垂直领域能力决定工具选择…...

【Python 初级函数详解】—— 参数沙漠与作用域丛林的求生指南

欢迎来到ZyyOvO的博客✨&#xff0c;一个关于探索技术的角落&#xff0c;记录学习的点滴&#x1f4d6;&#xff0c;分享实用的技巧&#x1f6e0;️&#xff0c;偶尔还有一些奇思妙想&#x1f4a1; 本文由ZyyOvO原创✍️&#xff0c;感谢支持❤️&#xff01;请尊重原创&#x1…...

极客大学 java 进阶训练营怎么样,图文详解

Spring 思维导图 Spring 源码学习笔记 有关微服务的面试题&#xff1a; Dubbo中zookeeper做注册中心&#xff0c;如果注册中心集群都挂掉&#xff0c;发布者和订阅者之间还能通信么&#xff1f;微服务学习笔记 有关分布式的面试题&#xff1a; 消息幂等:如何保证消息不被重复…...

机器人学习模拟框架 robosuite (3) 机器人控制代码示例

Robosuite框架是一个用于机器人模拟和控制的强大工具&#xff0c;支持多种类型的机器人。 官方文档&#xff1a;Overview — robosuite 1.5 documentation 开源地址&#xff1a;https://github.com/ARISE-Initiative/robosuite 目录 1、通过键盘或SpaceMouse远程控制机器人…...

玩转python: 几个案例-掌握贪心算法

什么是贪心算法 贪心算法是一种在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是全局最好或最优的算法策略。它不从整体最优上加以考虑&#xff0c;只做出在某种意义上的局部最优解。下面我们将通过几个案例…...

腾讯集团软件开发-后台开发方向内推

熟练掌握C/C/Java/Go等其中一门开发语言&#xff1b; TCP/UDP网络协议及相关编程、进程间通讯编程&#xff1b; 专业软件知识&#xff0c;包括算法、操作系统、软件工程、设计模式、数据结构、数据库系统、网络安全等 有一定了解的&#xff1a; 1、Python、Shell、Perl等脚本语…...

哈希碰撞攻防战——深入浅出Map/Set的底层实现

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 今天我们来学习Map/Set的底层实现 目录 问题一&#xff1a;hash会出现负数&#xff1f;数组越界 一&#xff1a;什么是二叉搜索树&#xff1f…...

深度解析Ant Design Pro 6开发实践

深度解析Ant Design Pro 6全栈开发实践&#xff1a;从架构设计到企业级应用落地 一、Ant Design Pro 6核心特性与生态定位&#xff08;技术架构分析&#xff09; 作为Ant Design生态体系的旗舰级企业应用中台框架&#xff0c;Ant Design Pro 6基于以下技术栈实现突破性升级&am…...

用大白话解释基础框架Spring Boot——像“装修套餐”一样简单

SpringBoot是什么&#xff08;SpringBoot类似装修公司的全包套餐&#xff09; SpringBoot是Java开发者的“装修神器”&#xff0c;可以快速搭建一个应用系统&#xff0c;不用自己亲自买钉子、水泥和瓷砖&#xff08;相当于传统的Spring框架的复杂配置&#xff09;&#xff0c;…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...