JAVA 10
局部变量类型推断
在java中,我们可以使用自动类型推断
public static void main(String[] args) {
var a = "hello world";
System.out.println("a = " + a);
}
但是注意,var 关键字必须位于有初始值设定的变量上,否则编译都不会通过。java终究不像JS那样进行动态推断,这种类型推断仅仅发生在编译期间,到最后编译完成还是会变成具体类型的。
var 关键字不能做为属性或成员变量使用,只能做为局部变量使用。
JAVA 11
Java11 是继 Java8 之后的又一个 TLS 长期维护版本,在Java 17出现之前,一直都是此版本做为广泛使用的版本,其中比较关键的是用于 Lambda 的形参局部变量语法。
用于Lambda的形参局部变量语法
在 Java10 我们认识了 var 关键字,它能够让局部变量自动进行类型推断,不过它不支持在 lambda 中使用,所以在 Java11 终于支持了。
public static void main(String[] args) {
Consumer<String> consumer = (var s) -> System.out.println(s.length());
consumer.accept("你好");
}
针对String类的方法增强
public static void main(String[] args) {
var str = "AB\nC \nD ";
// 判断是否字符串为空或者仅包含空格
System.out.println(str.isBlank());
str
// 根据字符串中的 \n 换行符进行切割,分为多个字符串,并转换为Stream进行操作
.lines()
.forEach(System.out::println);
// 根据传入次数,复制原有字符串并拼接到末尾 "AB\nC\nDAB\nC\nD"
System.out.println(str.repeat(2));
// 去除首位空格
System.out.println(str.strip());
// 去除首部空格
System.out.println(str.stripLeading());
// 去除尾部空格
System.out.println(str.stripTrailing());
}
全新的HttpClient使用
在 java9 的时候其实就已经引入了全新的 HttpClient API,用于取代之前比较老的HttpURLConnection类,新的API支持最新的HTTP2和WebSocket协议。
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
// 创建一个客户端
var httpClient = HttpClient.newHttpClient();
// 创建一个请求
var request = HttpRequest.newBuilder(new URI("http://www.baidu.com")).GET().build();
// 发送得到响应
var send = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(send.body());
}
java12
java 12-16这五个版本并非长期版本,所以很多特性都是一种处于实验性功能,12/13版本引入了一些实验性功能,并根据反馈进行调整,最后在后续版本中正式开放使用,其实就是体验服的那种感觉。
新的switch语法
新的语法可以大大方便我们的编写,但是还是美中不足的是不能支持范围匹配
/**
* 传入分数
* 90-100 优秀
* 70-90 良好
* 60-70 及格
* 0-60 差
**/
public static String old(int score){
score/=10;
String str;
switch (score){
case 10:
case 9:
str = "优秀";
break;
case 8:
case 7:
str = "良好";
break;
case 6:
str = "几个";
break;
default:
str = "不及格";
}
return str;
}
public static String java12(int score){
score/=10;
return switch (score){
case 10,9 -> "优秀";
case 8,7 -> "良好";
case 6 -> "几个";
default -> "不及格";
};
}
public static String java12_1(int score){
score/=10;
return switch (score){
case 10,9 -> "优秀";
case 8,7 -> "良好";
case 6 -> "几个";
default -> {
System.out.println("其他方式");
yield "不及格";
}
};
}
java13
文本块
当我们需要使用复杂字符串时,可能字符串中包含了很多需要转移的字符,比如双引号等,这时我们就可以使用三引号来囊括字符串
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
var s = """
dsafdsafdsa
dfdsafd
""fdsa \n \n dsfdsa
\r ffff \t dsfad
""";
System.out.println(s);
}
结果打印:
dsafdsafdsa
dfdsafd
""fdsa
dsfdsa
ffff dsfad
java14
新的 instanceof 语法
public boolean old(Object o) {
if (this == o) {return true;}
if (o instanceof User) {
User user = (User) o;
return user.name.equals(this.name);
}
return false;
}
public boolean java16(Object o) {
if (this == o) {return true;}
if (o instanceof User user) {
return user.name.equals(this.name);
}
return false;
}
空指针异常的改进
在旧版本中如果出现空指针异常,报错只会给我们空指针发生在哪一行,具体哪个变量为空并不会告诉我们,需要我们自己打debug,在新的版本中会明确告知我们。
记录类型 Record
继类、接口、枚举、注解之后的又一新类型来了,他的名字叫记录
,在java14中首次出场,这一出场,Lombok 的噩梦来了。 在实际开发中,很多类仅仅只是充当一个实体类罢了,保存的是一些不可变数据,比如我们从数据库中查询的账户信息,最后被映射为一个实体类
@Data
public class User {
private String name;
private Integer age;
}
Lombok 可以说时简化代码的神器,它能在编译时自动生成 get、set、构造器、toString()方法等,在编写这些实体类时,简直不要太好用,Record可以让我们不需要显式地定义构造函数、getters方法或equals和hashCode方法。所有这些都会由Records自动生成。
记录类型本质上也是一个普通类,不过是 final 类型且继承自 java.lang.Record抽象类的,他会在编译时,会自动编译出 get、hashCode、equals、toString等方法。
// 只能把字段写道括号中
public record User(String name,Integer age) {
public static void a(){
}
public static void main(String[] args) {
User user = new User("张三",2);
System.out.println(user.name());
System.out.println(user);
}
}
但有些功能还是没有办法与 Lombok 相比的,如 @SL4J,链式调用,无参构造函数不支持等。
java17
密封类型
密封类型可以说时java17正式推出的又一重磅类型,它在java15首次提出并测试了两个版本。
在java中,我们可以通过继承(extends关键字)来实现类的能力复用,扩展与增强。但有的时候,可能并不是所有的类我们都希望能够被继承。所以,我们需要对继承关系有一些限制的控制手段,而密封类的作用就是限制类的继承。实际上在之前我们如果不希望别人继承我们的类,可以直接添加 final 关键字。
这样有一个缺点,如果添加了 final 关键字,那么无论是谁,包括我们自己也是没办法实现继承的,但是现在我们有一个需求,只允许我们自己写的类继承,但是不允许别人写的类继承,这时该咋写?在java17之前想要实现就很麻烦。
# 旧版本
public final class A{
}
# 新版本 sealed
public sealed class A permits B {
}
# 继承 A
public final class B extends A {
}
public sealed class B extends A {
}
public non-sealed B extends A {
}
密封类型有以下要求:
- 可以基于普通类、抽象类、接口,也可以继承自其他接口的子类或是实现其他接口的类等。
- 必须有子类继承,且不能是匿名内部类或是lambda的形式
- sealed 写在原来 final 的位置,但不能和 final、non-sealed 关键字同时出现,只能选其一
- 继承的子类必须显示的标记为final(表示这个类不能被继承)、sealed(表示这个子类也可以有其他密封的或非密封的子类) 或是 non-sealed (表示这个子类不能有子类,但它可以被其他类继承)类型