var list = new ArrayList<String>();
- 声明时必须初始化
可以使用在:
- 具有初始化器的局部变量
- 增强型 for 循环中的索引变量
- 传统 for 循环中声明的局部变量
不能使用在:
- 推断方法的参数类型
- 构造函数参数类型推断
- 推断方法返回类型
- 字段类型推断
- 捕获表达式(或任何其他类型的变量声明)
建议:为了程序的易读性和可维护性,尽量显式定义变量类型。
将局部变量和 Lambda 表达式的用法进行了统一,并且可以将注释应用于局部变量和 Lambda 表达式
@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)
- @NonNull 注解可以标注在方法、字段、参数之上,表示对应的值不能为空;
- @Nullable 注解可以标注在方法、字段、参数之上,表示对应的值可以为空;
旧版:
新版:
//旧版:
int dayOfWeek;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
dayOfWeek = 5;
break;
case SATURDAY:
dayOfWeek = 6;
break;
case SUNDAY:
dayOfWeek = 7;
break;
default:
dayOfWeek = 0;
break;
}
//新版:
int dayOfWeek = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> 5;
case SATURDAY -> 6;
case SUNDAY -> 7;
default -> 0;
};
注意:
文本块就是以三个引号开始,并以三个引号结束的字符串字面量。
文本块减少了转义,大大提高了代码可读性,尤其是代码中对SQL、HTML、JSON字符串进行拼接的情况。
// 旧版
String sqlTemplate = "SELECT\n" +
" name,\n" +
" age,\n" +
" phone,\n" +
" wechat\n" +
"FROM\n" +
" csdn_user;";
// 新版
String sqlTemplate = """
SELECT
name,
age,
phone,
wechat
FROM
csdn_user;
""";
对 instanceof 的改进,主要目的是为了让创建对象更简单、简洁和高效,并且可读性更强、提高安全性。
// 旧版
// 每次在检查类型之后,都需要强制进行类型转换。
// 类型转换后,需要提前创建一个局部变量来接收转换后的结果,代码显得多余且繁琐。
if (person instanceof Student) {
Student student = (Student) person;
student.say();
// other student operations
} else if (person instanceof Teacher) {
Teacher teacher = (Teacher) person;
teacher.say();
// other teacher operations
}
// 新版
// 对 person 对象进行类型匹配,校验 person 对象是否为 Student 类型
// 如果类型匹配成功,则会转换为 Student 类型,并赋值给模式局部变量 student
if (person instanceof Student student) {
//这里的 student 变量只能在 if 块中使用,而不能在 else if/else 中使用
student.say();
// other student operations
} else if (person instanceof Teacher teacher) {
teacher.say();
// other teacher operations
}
如果 if 条件中有 && 运算符时,当 instanceof 类型匹配成功,模式局部变量的作用范围也可以相应延长,如下面代码:
if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}
注意:这种作用范围延长,并不适用于或 || 运算符,因为即便 || 运算符左边的 instanceof 类型匹配没有成功也不会造成短路,依旧会执行到||运算符右边的表达式.但是如果左边instanceof 类型匹配没有成功,局部变量并未定义赋值,此时使用会产生问题。
- Record 类型允许在代码中使用紧凑的语法形式来声明类,而这些类能够作为不可变数据类型的封装持有者。Record 这一特性主要用在特定领域的类上;
- 与枚举类型一样,Record 类型是一种受限形式的类型,主要用于存储、保存数据,并且没有其它额外自定义行为的场景下。
- 效果有些类似 Lombok 的 @Data 注解、Kotlin 中的 data class,但是又不尽完全相同,它们的共同点都是类的部分或者全部可以直接在类头中定义、描述,并且这个类只用于存储数据而已。
// 示例
public record Person(String name, int age) {
public static String address;
public String getName() {
return name;
}
}
// 编译后反编译的结果
public final class Person extends java.lang.Record {
private final java.lang.String name;
private final java.lang.String age;
public Person(java.lang.String name, java.lang.String age) { /* compiled code */ }
public java.lang.String getName() { /* compiled code */ }
public java.lang.String toString() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
public java.lang.String name() { /* compiled code */ }
public java.lang.String age() { /* compiled code */ }
}
可以得出,当用 Record 来声明一个类时,该类将自动拥有下面特征:
用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。
使用修饰符sealed,您可以将一个类声明为密封类。
密封的类使用关键字permits列出可以直接扩展它的类。
子类可以是最终的、非密封的或密封的。
继承了密封类的子类可以使用non-sealed修饰,这样任何类都可以继承这个子类。
// 旧版
public class Person { } //人
class Teacher extends Person { }//教师
class Worker extends Person { } //工人
class Student extends Person{ } //学生
// 新版
// 添加sealed修饰符,permits后面跟上只能被继承的子类名称
public sealed class Person permits Teacher, Worker, Student{ } //人
// 子类可以被修饰为 final
final class Teacher extends Person { }//教师
// 子类可以被修饰为 non-sealed,此时 Worker类就成了普通类,谁都可以继承它
non-sealed class Worker extends Person { } //工人
// 任何类都可以继承Worker
class AnyClass extends Worker{}
//子类可以被修饰为 sealed,同上
sealed class Student extends Person permits MiddleSchoolStudent,GraduateStudent{ } //学生
final class MiddleSchoolStudent extends Student { } //中学生
final class GraduateStudent extends Student { } //研究生
可以限制类的层次结构。