一、JDK关注的新特性
1.1搭建学习环境
JDK:JDK19
OpenJDK: https://jdk.java.net/19/
Liberica JDK: https://bell-sw.com/pages/downloads/ , 是一个OpenJDK发行版,为云原生,容器特别优化。 Maven:构建和依赖管理,版本选择3.6以上
配置本地仓库和阿里云镜像 IDEA2022.3.1Ultimate:主要的开发工具,我是30天试用版本
数据库:MySQL 5以上版本
火狐浏览器:版本用比较新的,中文版本。
文本工具:EditPlus, Sublime任意。
1.2有用的新特性
JDK8-19新增了不少新特性,这里我们把实际常用的新特性,给大家介绍一下。 包括以下几个方面:
- Java Record
- Swich开关表达式
- Text Block文本块
- var 声明局部变量
- sealed 密封类
1.2.1 Java Record
Java14中预览的新特性叫做Record,在Java中,Record是一种特殊类型的Java类。可用来创建不可变类,语法简短。参考JEP 39 5. Jackson 2.12支持Record类。
任何时候创建Java类,都会创建大量的样板代码,我们可能做如下:
- 每个字段的set,get方法
- 公共的构造方法
- 重写hashCode, toString(), equals()方法
Java Record避免上述的样板代码,如下特点:
- 带有全部参数的构造方法
- public访问器
- toString(),hashCode(),equals()
- 无set,get方法。没有遵循Bean的命名规范
- final类,不能继承Record,Record为隐士的final类。除此之外与普通类一样
- 不可变类,通过构造创建Record
- final属性,不可修改
- 不能声明实例属性,能声明static成员
IDEA创建新的Maven工程 Lession01-feature
1.2.1.1 看看Record怎么用
IDEA新建Class,选择类Record
step1: 创建Student Record
step2:创建Record对象
现在能查看控制台输出:
lisi = Student[id=1001, name=lisi, email=lisi@qq.com, age=20]
zhangsan = Student[id=1002, name=zhangsan, email=lisi@qq.com, age=20]
lisi.equals(zhangsan) = false
lisi.name() = lisi
zhangsan.name() = zhangsan
Record通过构造方法创建了只读的对象,能够读取每个属性,不能设置新的属性值。 Record用于创建不可变的对象,同时减少了样板代码。
Record对每个属性提供了public访问器, 例如lisi.name()
1.2.1.2Instance Methods
Record是Java类,和普通Java类一样定义方法。下面定义方法concat,将姓名和年龄一起打印输出。
我们创建普通的方法concat,将name和age连接为一个字符串输出。
step1:创建实例方法
step2: 调用实例方法
最后控制台输出: 姓名:lisi,年龄是:20
1.2.1.3静态方法 Static Method
Record类定义静态方法,试用静态方法与普通类一样。
step1: 创建静态方法
step2:测试静态方法
1.2.1.4 Record的构造方法
我们可以在Record中添加构造方法, 有三种类型的构造方法分别:是紧凑的,规范的和定制构造方法
- 紧凑型构造方法没有任何参数,甚至没有括号。
- 规范构造方法是以所有成员作为参数
- 定制构造方法是自定义参数个数
step1: 紧凑和定制构造方法
step2:编译Student.java -> Student.class
1.2.1.5Record与Lombok
Java Record是创建不可变类且减少样板代码的好方法。Lombok是一种减少样板代码的工具。两者有表面上的重叠部分。可能有人会说Java Record会代替Lombok. 两者是有不同用途的工具。
Lombok提供语法的便利性,通常预装一些代码模板,根据您加入到类中的注解自动执行代码模板。这样的库纯粹是为了方便实现POJO类。通过预编译代码。将代码的模板加入到class中。
Java Record是语言级别的,一种语义特性,为了建模而用,数据聚合。简单说就是提供了通用的数据类,充当“数据载体",用于在类和应用程序之间进行数据传输。
1.2.1.6Record实现接口
Java Record可以与普通类一样实现接口,重写接口的方法。
step1: 创建新的接口,定义一个规范方法。
step2: 创建新的Record实现接口,重写接口的方法,实现当前Record有关的业务逻辑
ProductRecord实现print()方法,打印商品详情。
step3:测试print方法
1.2.1.7Local Record
Record可以作为局部对象使用。在代码块中定义并使用Record,下面定义一个SaleRecord
step1:定义Local Record
控制台输出: 销售记录 = SaleRecord[saleId=S22020301, productName=手机, money=3000.0]
1.2.1.8嵌套Record
多个Record可以组合定义, 一个Record能够包含其他的Record。
我们定义Record为Customer,存储客户信息,包含了Address和PhoneNumber两个Record
step1:定义Record
step2: 创建Customer对象
控制台输出: 客户 = Customer[id=C1001, name=李项, phoneNumber=PhoneNumber[areaCode=010, number=400-8080-105], address=Address[city=北京, address=大兴区凉水河二街9号10栋三层, zipcode=100176]]
1.2.1.9instanceof 判断Record类型
instanceof 能够与 Java Record一起使用。编译器知道记录组件的确切数量和类型。
step1:声明Person Record,拥有两个属性name和age
step2: 在一个业务方法判断当是Record类型时,继续判断age年龄是否满足18岁。
instanceof 还可以下面的方式
step3: 测试代码
控制台输出: 控制台输出flag为true
处理判断中Record为null
Java Record能够自动处理null。
step1:record为null
控制台输出eligible为false ,Debug调试代码,发现if语句判断为false,不执行 。
总结
- abstract类java.lang.Record是所有Record的父类。
- 有对于equals(),hashCode(),toString()方法的定义说明
- Record类能够实现 java.io.Serializable序列化或反序列化
- Record支持泛型,例如 record Gif( T t ) { }
- java.lang.Class类与Record类有关的两个方法:
1.2.2 Switch
Switch的三个方面,参考:JEP 361
- 支持箭头表达式
- 支持yied返回值
- 支持Java Record
1.2.2.1 箭头表达式,新的case标签
Switch新的语法,case label -> 表达式|throw 语句|block
case label_1, label_2, ..., label_n -> expression;|throw-statement;|block
step1:新的case 标签
week:表示周日(1)到周六(7),1和7是休息日,其他是工作日。如果1-7以外为无需日期
1.2.2.2 yeild返回值
yeild让switch作为表达式,能够返回值
语法
变量 = switch(value) { case v1: yield 结果值; case v2: yield 结果值;case v3,v4,v5.. yield 结果值 }
示例: yield返回值,跳出switch块
无需中间变量, switch作为表达式计算,可以得到结果。yield是表达式的返回值
示例:多表达式, case 与yield 结合使用
提示:
case 标签-> 与 case 标签:不能混用。 一个switch语句块中使用一种语法格式。 switch作为表达式,赋值给变量,需要yield或者case 标签-> 表达式。->右侧表达式为case返回值。
示例:
1.2.2.3 Java Record
switch表达式中使用record,结合 case 标签-> 表达式,yield实现复杂的计算
step1: 准备三个Record
step2: switch record
case Line , Rectangle,Shape 在代码块执行多条语句,或者箭头->表达式。
1.2.3 Text Block
Text Block处理多行文本十分方便,省时省力。无需连接 "+",单引号,换行符等。Java 15 ,参考JEP 378.
1.2.3.1 认识文本块
语法:使用三个双引号字符括起来的字符串.
例如:
文本块定义要求:
- 文本块以三个双引号字符开始,后跟一个行结束符。
- 不能将文本块放在单行上
- 文本块的内容也不能在没有中间行结束符的情况下跟随三个开头双引号
三个双引号字符""" 与两个双引号""的字符串处理是一样的。与普通字符串一样使用。例如equals() , "==" , 连接字符串(”+“), 作为方法的参数等。
1.2.3.2 文本块与普通的双引号字符串一样
Text Block使用方式与普通字符串一样,==,equals比较,调用String类的方法。
step1:字符串比较与方法
step2:输出结果
1.2.3.3 空白
- JEP 378中包含空格处理的详细算法说明。
- Text Block中的缩进会自动去除,左侧和右侧的。
- 要保留左侧的缩进,空格。将文本块的内容向左移动(tab键)
示例:
示例2:indent()方法
输出:
red
green
blue
1.2.3.4 文本块的方法
Text Block的格式方法formatted()
String stripIndent():删除每行开头和结尾的空白
String translateEscapes() :转义序列转换为字符串字面量
1.2.3.5 转义字符
新的转义字符"\",表示隐士换行符,这个转义字符被Text Block转义为空格。通常用于是拆分非常长的字符串文本 ,串联多个较小子字符串,包装为多行生成字符串。 新的转义字符,组合非常长的字符串。
示例
输出
Spring Boot是一个快速开发框架 基于Spring框架,创建Spring应用 内嵌Web服务器,以jar或war方式运行
总结:
- 多行字符串,应该使用Text Block
- 当Text Block可以提高代码的清晰度时,推荐使用。比如代码中嵌入SQL语句
- 避免不必要的缩进,开头和结尾部分。
- 使用空格或仅使用制表符 文本块的缩进。混合空白将导致不规则的缩进。
- 对于大多数多行字符串, 分隔符位于上一行的右端,并将结束分隔符位于文本块单独行上。例如:
1.2.4 var
在JDK 10及更高版本中,您可以使用var标识符声明具有非空初始化式的局部变量,这可以帮助您编写简洁的代码,消除冗余信息使代码更具可读性,谨慎使用.
1.2.4.1 var 声明局部变量
var特点
- var是一个保留字,不是关键字(可以声明var为变量名)
- 方法内声明的局部变量,必须有初值
- 每次声明一个变量,不可复合声明多个变量。 var s1="Hello", age=20; //Error
- var动态类型是编译器根据变量所赋的值来推断类型
- var代替显示类型,代码简洁,减少不必要的排版,混乱。
var优缺点
- 代码简洁和整齐。
- 降低了程序的可读性(无强类型声明)
示例:
1.2.4.2 使用时候使用var
- 简单的临时变量
- 复杂,多步骤逻辑,嵌套的表达式等,简短的变量有助理解代码
- 能够确定变量初始值
- 变量类型比较长时
示例:
1.2.5 sealed
sealed 翻译为密封,密封类(Sealed Classes)的首次提出是在 Java15 的 JEP 360 中,并在 Java 16 的 JEP 397 再次预览,而在 Java 17 的 JEP 409 成为正式的功能。
Sealed Classes主要特点是限制继承
Sealed Classes主要特点是限制继承,Java中通过继承增强,扩展了类的能力,复用某些功能。当这种能力不受控。与原有类的设计相违背,导致不预见的异常逻辑。
Sealed Classes限制无限的扩张。
Java中已有sealed 的设计
- final关键字,修饰类不能被继承
- private限制私有类
sealed 作为关键字可在class和interface上使用,结合permits 关键字。定义限制继承的密封类
1.2.5.1Sealed Classes
sealed class 类名 permits 子类1,子类N列表 {}
step1::声明sealed Class
permits表示允许的子类,一个或多个。
step2::声明子类
子类声明有三种
- final 终结,依然是密封的
- sealed 子类是密封类,需要子类实现
- non-sealed 非密封类,扩展使用,不受限
示例:
密封类不支持匿名类与函数式接口
1.2.5.2 Sealed Interface
密封接口同密封类
step1:声明密封接口
step2:实现接口
以上类和接口要在同一包可访问范围内。