导读
最近网上开始了大量的关于Java19的讨论,我也想着用了Java8这么久该接受一点新的东西了,于是便开始研究了起来
Java 19
Java19是一个免费版本。下面是JDK19的支持图
(来源:https://www.bilibili.com/video/BV1V84y1B7dD?t=39.9)
可以看到目前较为长期的免费支持版本是Java17,而下一个版本是Java21(免费支持于2027年结束)
开始研究
在网上查找了大量的文件并对JDK9-19做了些整理打算从以下几个功能去了解从Java8-Java19的发展
- 数组转列表和列表转数组(Java 9)
- var关键字(Java 10)
- yield关键字(Java 13)
- Record(记录)类(Java 14)
- case的多个值匹配(Java 14)
- case返回值(Java 14,17)
- Sealed(密闭)类(Java 15)
- switch类型判断(Java 17)
- 文本块(Java 17)
- switch复杂表达式(Java 19 第三次预览(正式版Java 19该功能被移除,不排除以后会加入的可能))
数组转列表和列表转数组(Java 9)
@Test
public void test(){
String[] strings={"你好","早","这foe及","vdsoijfdois"};
List stringList=List.of(strings);//JDK9
System.out.println(stringList);
}
List.of
为JDK9带来的新功能,他可以将数组转换为对应的列表(List),但是,转换后的List是不能改变的。
var关键字(Java 10)
var关键字可以不用显式地声明变量的类型。举例:
public class People{
private String name;
private int age;
//Getter Setter...
}
public static void main(String[] args){
var people=new Student();
people.setSid("321321");
//...
}
虽说不会显示地声明类型,但实际上,变量的类型是确定的,因为:
- 使用var声明的变量必须被初始化
- 初始化时是什么类型以后再赋值时必须是这个类型或者这个类的子类
yield关键字(Java 13)
yield
目前貌似只适用于case分支中,举例:
@Test
public void returedSwitch2(){
Scanner scanner=new Scanner(System.in);
int i = scanner.nextInt();
int result=switch (i){
case 1->{
System.out.printf("输入的是%d",i);
yield i+3;
}
case 2->{
System.out.printf("输入的是%d呀",i);
yield i-5;
}
default -> i;
};
System.out.printf("result=%d",result);
}
它的作用是将case分支中yield后面的值作为返回值返回回来。如果要使用yield关键字或者想让switch返回一个值则case后面的:
必须被替换为->
。
->
这个符号在switch中的应用是Java 12带来的,它的作用是让case的执行唯一,直白说就是不会再“逢break停”。
举个例子:
Scanner scanner=new Scanner(System.in);
String next = scanner.next();
//part 1
String response=switch (next){
case "你好","早上好","中午好","下午好"->"你好呀";
case "我不是很好","我不好","我难受"->"不要伤心嘛";
default -> "需要帮助吗?";
};
System.out.println(response);
System.out.println("与上面的对比");
//part 2
switch (next){
case "你好","早上好","中午好","下午好":
System.out.println("你好呀");
case "我不是很好","我不好","我难受":System.out.println("不要伤心嘛");break;
default :System.out.println("需要帮助吗?") ;break;
};
part 1就是新的switch语法,它避免了大量的break出现在代码中,如果case "你好","早上好","中午好","下午好"
满足,则返回"你好呀"
,而不像原来那样把所有结果都返回。对于同一个需求,part1的写法显然比part2的写法方便一些。
Record(记录)类(Java 14)
record
关键字可以将某个类标识为记录类,被该关键字标记的类会自动生成Getter和Setter以及hashCode()
,toString()
方法,同时,该类的值不会再被改变!
举例:
//Record类只能这么定义
public record StudentRecord(String id, String name, int age) {
}
@Test
public void recordClass(){
StudentRecord sr=new StudentRecord("123","张三",12);
System.out.println(sr);
System.out.printf("""
id:%s,姓名:%s
年龄:%d
""",sr.id(),sr.name(),sr.age());
}
这个类在前后端分离项目中是很有用的。
case的多个值匹配(Java 14)与case返回值(Java 14,17)
其实从Java 12开始就对switch进行改动了,在Java 14中,switch可以对多个值进行比较了,相比于以前的case 1:case 2...这种简化了很多,在yield关键字章节使用的就是这个特性。
String response=switch (next){
case "你好","早上好","中午好","下午好"->"你好呀";
case "我不是很好","我不好","我难受"->"不要伤心嘛";
default -> "需要帮助吗?";
};
下面的写法也是正确的
switch (next){
case "你好","早上好","中午好","下午好":System.out.println("你好呀");
case "我不是很好","我不好","我难受":System.out.println("不要伤心嘛");
default :System.out.println( "需要帮助吗?");
};
第一个写法是可以将"你好呀"、"不要伤心嘛"这类字符串作为switch返回值赋值给response的。
第二个写法则只能进行多值匹配,switch没办法返回任何值,原因可以参见yield关键字章节
Sealed(密闭)类(Java 15)
有时候可能不希望某个接口或者类被某个类实现或者继承,那么,密闭类就可以满足这个要求。
public sealed interface AnimalMethods permits Animal{
public void call();
}
public sealed class Animal implements AnimalMethods permits Sheep,Cow{
private String name;
private int age;
private Date birthDate;
//Getter,Setter...
@Override
public void call() {
System.out.println("任何动物都有叫声");
}
}
public non-sealed class Sheep extends Animal{
@Override
public void call() {
System.out.println("咩~");
}
}
public non-sealed class Cow extends Animal{
@Override
public void call() {
System.out.println("牟~");
}
}
首先我定义了一个密闭接口AnimalMethods
并限制只能让Animal类或者接口来实现或者继承它。
然后创建一个类Animal
实现接口AnimalMethods
,同时Animal
类也是一个密闭类,要求只有Sheep
类和Cow
类可以继承这个类。
最后创建Sheep
和Cow
类。
密闭类有这样的性质:
- seald关键字不能和final以及record关键字一起使用
- seald关键字必须和permits关键字一起使用
- 密闭类必须有子类且必须限制所有子类,密闭接口必须有子接口或者实现类并且限制所有子接口以及实现类。
以上面的代码为例,将public sealed class Animal implements AnimalMethods permits Sheep,Cow
改为public sealed class Animal implements AnimalMethods permits Sheep
同时保持继承关系不变,那么会编译失败,因为,Cow
类也是Animal
类的子类,因此permites
也必须包含Cow
类 - 使用seald标记的类或接口其子类或子接口必须是
seald
、non-seald
(非密闭)、final
中的一种
switch类型判断(Java 17)
switch可以代替instanceof
关键字对对象的类型进行判断。
需要注意的是,在Java 19正式版中并不支持这个功能。
Object number=new Student();
//这个功能目前在孵化中
var result=switch (number){
case null-> "啊哦";
case Integer i->"int";
case Student s->"Student";
default -> "Oops";
};
System.out.println(result);
这确实是一个很大的改进,希望以后可以实装
文本块(Java 17)
在Record(记录)类(Java 14)章节可以看到文本块的影子,使用"""
(3个英文双引号)就可以定义一个文本块。它的目的是为了解决“使用+
链接带有转义字符的字符串导致的代码难看的问题。”
在以前,想要输出含有转义字符的字符串同时还要方便代码编写是不可能的,只能通过+
完成,比如:
public static void main(String[] args){
System.out.printf("姓名:%s"+
"性别:%c"+
"年龄:%d","张三",'m',18);
}
很痛苦,这样写代码很难看,有了文本块后就可以这么写:
public static void main(String[] args){
System.out.printf("""
姓名:%s
性别:%c
年龄:%d
""","张三",'m',18);
}
方便了很多,而且代码也不是很难看。
(你问我printf
是新功能吗?——不是!)
switch复杂表达式(Java 19 第三次预览(正式版Java 19该功能被移除,不排除以后会加入的可能))
你是否被大量的if-else所困扰?现在,解决方案来了,你可以使用switch进行表达式的判断了。
Student student=new Student();
student.setAge(12);
String result= switch (student){
case Student s when s.getAge()>=18->"已成年";
default -> "未成年";
};
System.out.println(result);
Student student=new Student();
student.setAge(12);
if(student.getAge>=18){
System.out.println("已成年");
else{
System.out.println("未成年");
}
这个例子很简单,如果你要进行多种判断的话无疑这种写法是最方便的也更整洁。
但是,在正式的Java19中不支持这个功能。
评价
以上只是介绍了这些新特性的一小部分,实际上,这几个版本都对性能、开发复杂程度做了一定的优化。同时,也让Java的开发变得简单了一些。
关于市场:由于目前国内大部分的公司所开发的项目使用的还是Java 8。因此,市场上在相当长的一段时间内还是会青睐Java 8。所以对于小白而言还是以Java 8的学习为主,高版本的Java感兴趣的话可以自己去了解。
对于框架:Springboot 3已经明确要求使用Java 17以上,因此,在不久的将来,如果依然使用Springboot开发的话那么Java 8会被淘汰掉。由于Java 19刚刚发布不久,很多框架(如Mybatis-plus)还没有做支持,所以,最近不要使用Java19+Springboot做一些项目,过一段时间之后再看看。
代码
https://blacol.lanzoue.com/iysxK0ibyxgd