目录
0、有用的新特性
一、Record
1.1、Record的介绍:
1.2、Record的声明:
1.3、Record的创建:
1.4、Record使用举例:
1.5、Record-实例方法、静态方法
1.6、Record-三类构造方法
1.6.1、紧凑型构造、定制构造方法:
1.6.2、测试一下:
1.7、Record和Lombok的对比:
1.8、Record类型实现接口
1.8.1、step1: 创建接口,定义一个抽象方法:
1.8.2、step2: 创建Record 实现接口:
1.8.3、step3:测试方法::
1.9、Local Record:
1.10、嵌套Record:
1.11、 instanceof 判断 Record 类型
1.12、Switch、Record、yield实现复杂计算举例:
0、有用的新特性
JDK8-19 新增了不少新特性,这里我们把实际常用的新特性,给大家介绍一下,包括以下几个方面:
- Java Record
- Swich 开关表达式
- Text Block 文本块
- var 声明局部变量
- sealed 密封类
一、Record
1.1、Record的介绍:
Java14 中预览的新特性叫做 Record,在 Java 中,Record 是一种特殊类型的 Java 类。可用来创建不可变类,例如这个类中的属性值,一经赋值后不可再改变了。
任何时候创建 Java 类,都会创建大量的样板(样例)代码,我们可能会使用Lombok简化:
- 每个字段的 set,get 方法
- 公共的构造方法
- 重写 hashCode, toString(), equals()方法
Lombok是通过插件和预编译的方式实现的,不是语言级别的,而Record是语言级别的Lombok,可以使用Record代替Lombok, 简化样例代码的编写、简化开发,如下特点:
- 带有全部参数的构造方法
- public 访问器:属性的访问是通过公共的方法
- 在编译Record过程中,会生成toString(),hashCode(),equals()等方法
- 没有遵循 Bean 的命名规范,无 set,get 方法
- 类以及所有的属性都是final修饰的, Record不能被继承,Record 为隐士的 final 类。除此之外与普通类一样
- 不可变类,不能被继承,通过构造创建 Record
- final 属性,能读它的属性,但是不可修改
- 不能声明实例属性,能声明 static 静态成员
1.2、Record的声明:
Record是JDK14的特性,所以你的jdk语言级别必须是14以上,否则就没有Record选项:
现在就有了:
Record是用来作为数据的载体,存储数据用的,创建方式如下:
public record Student(Integer id,String name,String email,Integer age) {
//1、小括号里面是它的构造方法
//2、使用record关键字,代表Student它是一个record类型
//3、不需要做其它的任何操作,record类型就创建好了,包含四个属性
}
1、小括号里面是它的构造方法
2、使用record关键字,代表Student它是一个record类型
3、不需要做其它的任何操作,record类型就创建好了,包含四个属性
我们现在来单元测试一下,alt+回车:
1.3、Record的创建:
创建Record对象和创建普通的java对象一模一样:
public class StudentTest {
@Test
public void testRecord() {
Student lisi = new Student(1001,"lisi","lisi@qq.com",20);
//Student[id=1001, name=lisi, email=lisi@qq.com, age=20]
System.out.println(lisi);
}
}
现在lisi这个对象,他的四个属性是固定好的了,只能读取,无法修改!现在我如何来读取他的四个属性呢,注意:
1、Record类型没有遵循Java Bean 的命名规范,无 set,get 方法,我们通过Public访问器来获取属性值;
2、因为没有set方法,所以通过Record创建的对象,属性值是不可变的,这样Record对象在使用上也就更加安全;
3、Record重写了hashCode, toString(), equals()方法,你输出lisi,其实是调用的lisi.toString()方法;
public class StudentTest {
@Test
public void testRecord() {
Student lisi = new Student(1001,"lisi","lisi@qq.com",20);
//Student[id=1001, name=lisi, email=lisi@qq.com, age=20]
System.out.println(lisi);
//无set、get方法,通过Public访问器来获取属性值,这些都是公共的方法:
Integer id = lisi.id();
String name = lisi.name();
System.out.println("id =" + id);
System.out.println("name =" + name);
}
}
1.4、Record使用举例:
@Test
public void testRecord() {
Student lisi = new Student(1001,"lisi","lisi@qq.com",20);
System.out.println("lisi:" + lisi);
Student lifang = new Student(1002,"lifang","lifang@qq.com",22);
System.out.println("lifang:" + lifang.toString());
System.out.println(lifang.equals(lisi));//false
Student lisi2 = new Student(1001,"lisi","lisi@qq.com",20);
System.out.println(lisi2.equals(lisi));//true
System.out.println(lisi2.age());
System.out.println(lifang.name());
}
Record 是 Java 类,和普通 Java 类一样可以定义实例方法,也可以定义静态方法:
1.5、Record-实例方法、静态方法
public record Student(Integer id,String name,String email,Integer age) {
//1、小括号里面是它的构造方法
//2、使用record关键字,代表Student它是一个record类型
//3、不需要做其它的任何操作,record类型就创建好了,包含四个属性
//实例方法,concat连接字符串:
public String concat(){
return String.format("姓名为:%s,年龄为:%d",this.name,this.age);
}
//静态方法,把email转为大写:
public static String emailToUpperCase(String email){
return Optional.ofNullable(email).orElse("no email").toUpperCase();
}
}
@Test
public void testRecord01(){
Student lisi = new Student(1001,"lisi","lisi@qq.com",23);
System.out.println(lisi.concat());
System.out.println(Student.emailToUpperCase("dddd@qq.com"));
}
1.6、Record-三类构造方法
- 紧凑型构造方法没有任何参数,甚至没有括号。
- 规范构造方法是以所有成员作为参数(自带了)
- 定制构造方法是自定义参数个数
1.6.1、紧凑型构造、定制构造方法:
public record Student(Integer id,String name,String email,Integer age) {
//1、小括号里面是它的构造方法
//2、使用record关键字,代表Student它是一个record类型
//3、不需要做其它的任何操作,record类型就创建好了,包含四个属性
//实例方法,concat连接字符串:
public String concat(){
return String.format("姓名为:%s,年龄为:%d",this.name,this.age);
}
//静态方法,把email转为大写:
public static String emailToUpperCase(String email){
return Optional.ofNullable(email).orElse("no email").toUpperCase();
}
//紧凑型构造方法:
public Student{
//注意,紧凑型构造方法是没有小括号,也没有任何的参数,直接写构造方法的执行体
System.out.println("id:" + id);
if(id < 1){
throw new RuntimeException("id<1 No!!");
}
}
//自定义构造方法
public Student(Integer id, String name){
//我们在自定义构造方法中去调用全参构造方法:
this(id,name,null,null);
}
}
1.6.2、测试一下:
@Test
public void testRecord02() {
Student student = new Student(2001,"xiaoHong");
System.out.println("student:" + student);
}
通过这个输出,你可以发现,它会先把紧凑型构造方法先执行, 再执行定制构造方法
如果你id传一个小于1的:
为什么会出现这种情况呢,我们来看一下编译后的class:
其实是进行了一个合并,把紧凑型构造方法和(规范)全参构造方法进行了合并:
public record Student(Integer id, String name, String email, Integer age) {
public Student(Integer id, String name, String email, Integer age) {
System.out.println("id:" + id);
if (id < 1) {
throw new RuntimeException("id<1 No!!");
} else {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
}
public Student(Integer id, String name) {
this(id, name, (String)null, (Integer)null);
}
public String concat() {
return String.format("姓名为:%s,年龄为:%d", this.name, this.age);
}
public static String emailToUpperCase(String email) {
return ((String)Optional.ofNullable(email).orElse("no email")).toUpperCase();
}
public Integer id() {
return this.id;
}
public String name() {
return this.name;
}
public String email() {
return this.email;
}
public Integer age() {
return this.age;
}
}
1.7、Record和Lombok的对比:
00
1.8、Record类型实现接口
举例步骤:step1: 创建新的接口,定义一个规范方法。step2: 创建新的 Record 实现接口,重写接口的方法,实现当前 Record 有关的业务逻辑
1.8.1、step1: 创建接口,定义一个抽象方法:
public interface PrintInterface {
//输出自定义的商品信息
void print();
}
1.8.2、step2: 创建Record 实现接口:
创建Record 实现接口,重写接口的方法,实现当前 Record 有关的业务逻辑:
public record ProductRecord(Integer id,String name,Integer qty) implements PrintInterface{
@Override
public void print() {
StringJoiner joiner = new StringJoiner("-");
String s = joiner.add(id.toString()).add(name).add(qty.toString()).toString();
System.out.println("There is the shopping information:" + s);
}
}
1.8.3、step3:测试方法::
@Test
public void testRecord04(){
ProductRecord product = new ProductRecord(1001,"iphonePuls",6666);
product.print();
1.9、Local Record:
Record 可以作为局部对象使用,你可以在代码块中或者方法体中来定义Record类型并使用:
@Test
public void testRecord05(){
//定义local Record:
record SaleRecord(String saleId,String productName,Double money){};
//创建对象:
SaleRecord sale = new SaleRecord("S001","iphone14",6666.02);
//SaleRecord[saleId=S001, productName=iphone14, money=6666.02]
System.out.println(sale);
}
1.10、嵌套Record:
如果你需要存储更多的数据,你可以使用嵌套Record:即多个 Record 可以组合定义, 一个 Record 能够包含其他的 Record:
public record Address(String city,String add,String zipcode) {
//城市、地址、邮编
}
public record PhoneNumber(String areaCode,String number) {
//区域码,电话号码
}
public record Consumer(String id, String name, PhoneNumber number,Address address) {
}
测试:
@Test
public void testRecord06(){
Address address = new Address("北京","大兴区凉水河二街-8号10栋","100176");
PhoneNumber phoneNumber = new PhoneNumber("010","400-8080-105");
Consumer consumer = new Consumer("c10001","李四",phoneNumber,address);
System.out.println(consumer);
System.out.println("客户姓名为:" + consumer.name());
System.out.println("客户联系电话为:" + consumer.number().number());
System.out.println("客户地址为:" + consumer.address().add());
}
1.11、 instanceof 判断 Record 类型
1.12、Switch、Record、yield实现复杂计算举例:
备注:没学过新特性Switch的同学可以先看本人此篇文章:http://t.csdnimg.cn/As9Ls
@Test
public void testSwitch01(){
Line line = new Line(10,20);
Rectangle rectangle = new Rectangle(20,50);
Shape shape = new Shape(50,80);
Object obj = line;
int result = switch(obj){
case Line(int x, int y)->{
System.out.println("图象是Line,x:" + x + ", y:" + y);
yield x + y;
}
case Rectangle(int w, int h)-> 2*(w + h);
case Shape(int x, int y)->{
System.out.println("图像是shape");
yield x*y;
}
default -> 0;
};
System.out.println("result = " + result);
}
如果Object obj = new String(); 结果为: