public abstract sealed class Color permits Red, Blue, Yellow
也就是说,只有 Red、Blue 和 Yellow 可以继承这个类,其他类想要继承它都无法通过编译。
你也可以不使用 permits 关键字,然后将类定义与类放在相同的文件中,如下所示:
public abstract sealed class Color {…}
… class Red extends Color {…}
… class Blue extends Color {…}
… class Yellow extends Color {…}
注意,这些子类并不是嵌套在封印类中,而是放在类定义之后。这与使用关键字 permit 是一样的效果,可以扩展 Color 的类只有 Red、Blue 和 Yellow。
那么,封印类通常用在哪里?通过限定继承规则,同时也限定了封装规则。假设你正在开发一个库,并且需要将抽象类 Color 包含在其中。你知道 Color 这个类以及哪些类需要扩展它,但如果它被声明为 public 的,那么你有什么办法可以阻止外部代码扩展它?
如果有人误解了它的用途并用 Square 对它进行了扩展,该怎么办?这符合你的意图吗?或者你其实是想让 Color 保持私有?但即使是这样,包级别的可见性也不能避免所有问题。如果后来有人对这个库进行了扩展了该怎么办?他们如何能够知道你只打算让一小部分类集成 Color?
封印类不仅可以保护你的代码不受外部代码的影响,还是一种向你可能从未见过的人传达意图的方式。如果一个类是封印的,你是在传达只有某些类可以扩展它。这种健壮性可以确保在多年以后任何阅读你代码的人都会理解代码的严谨。
2:增强的空指针异常
增强的 空指针异常 是一个有趣的更新——不会太复杂,但仍然很受欢迎。这个增强在 Java 14 中正式发布,提高了空指针异常 (NullPointerException,简称 NPE) 的可读性,可以打印出在抛出异常位置所调用的方法的名称和空变量的名称。例如,如果你调用 a.b.getName(),而 b 为空,那么异常的堆栈跟踪信息会告诉你调用 getName() 失败,因为 b 是空的。
我们都知道,NPE 是一种非常常见的异常,虽然在大多数情况下找出导致抛出异常的根源并不难,但你会时不时地遇到同时有两三个可疑变量的情况。你进入调试模式,开始查看代码,但问题很难重现。你只能试着回忆最初做了什么导致抛出 NPE 的。
如果你能提前获得这些信息,就不用这些麻烦地调试了。这就是这个特性的闪光点:不用再猜测 NPE 是从哪里抛出来的。在关键时刻,当你遇到难以重现的异常场景时,你就有了解决问题所需的一切。
这绝对是个救星!
3:switch 表达式
希望你耐心听我说几句——switch 表达式(在 Java 12 中预览,并正式添加到 Java 14 中) 是 switch 语句和 lambda 之间的某种结合。真的,当我第一次向别人描述 switch 表达式时,我的说法是他们把 switch 语句 lambda 化了。请看下面这个语法:
String adjacentColor = switch (color) {
case Blue, Green -> “yellow”;
case Red, Purple -> “blue”;
case Yellow, Orange -> “red”;
default -> “Unknown Color”;
};
现在明白我的意思了吗?
一个明显的区别是没有了 break 语句。switch 表达式延续了 Oracle 让 Java 语法更简洁的趋势。Oracle 非常讨厌大多数 switch 语句包含很多的 CASE BREAK、CASE BREAK、CASE BREAK……。
老实说,他们讨厌这个是对的,因为人们很容易在这个地方犯错。我们当中是否有人敢说他们从来没有遇到过这种情况:忘记在 switch 里添加 break 语句,只有当代码在运行时发生崩溃才知道?switch 表达式通过一种有趣的方式修复了这个问题,你只需要用逗号隔开同一个代码块里所有的值。没错,不需要使用 break 了!它会替你处理好!
switch 表达式还新增了 yield 关键字。如果一个 case 进入了一个代码块,yield 将被作为 switch 表达式的返回语句。例如,如果我们将上面的代码稍作修改:
String adjacentColor = switch (color) {
case Blue, Green -> “yellow”;
case Red, Purple -> “blue”;
case Yellow, Orange -> “red”;
default -> {
System.out.println(“The color could not be found.”);
yield “Unknown Color”;
}
};
在默认 case 里,System.out.println() 方法将被执行,adjacentColor 变量最终的值是“Unknown Color”,因为这是 yield 返回的结果。
总的来说,switch 表达式是一种更简洁的 switch 语句,但它不会取代 switch 语句,这两种语句都可用。
4:文本块
文本块 特性在 Java 13 中预览,并正式添加到 Java 15 中,它可以简化多行字符串的写法,支持换行,并在不需要转义字符的情况下保持缩进。要创建一个文本块,只需要这样:
String text = “”"
Hello
World"“”;
注意,这个变量仍然是一个字符串,只是它隐含了换行和制表符。同样,如果我们想要使用引号,也不需要转义字符:
String text = “”"
You can “quote” without complaints!“”"; // You can “quote” without complaints!
唯一需要使用反斜杠转义字符的地方是当你想要在文本块里包含"“”:
String text = “”"
The only necessary escape is “”",
everything else is maintained.“”";
除此之外,你可以调用 String 的 format() 方法,用动态内容替换文本块中的占位符:
String name = “Chris”;
String text = “”"
My name is %s.“”".format(name); // My name is Chris.
每行后面的空格都会被剪切掉,除非你指定了’\s’,这是文本块的一个转义字符:
String text1 = “”"
No trailing spaces.
Trailing spaces. \s"“”;
那么,在什么情况下会使用文本块呢?除了能够对大块的文本进行格式化外,将代码片段粘贴到字符串中也变得非常容易。因为缩进被保留了,如果你要写一个 HTML 或 Python 代码块,或使用其他任何语言,你都可以按照正常的方式写好它们,然后用"""把它们括起来,就可以保留代码的格式。你甚至可以用文本块来编写 JSON,并使用 format() 方法轻松地插入值。
总的来说,这是个一个很方便的特性。虽然文本块看起来只是一个小功能,但从长远来看,类似这种可以提升开发效率的小功能会逐渐增加。
5:record 类
record 类 在 Java 14 中预览,并正式添加到 Java 16 中,是一种数据类,处理所有与 POJO 相关的样板代码。也就是说,如果你声明了一个 record 类:
public record Coord(int x, int y) {
}
equals() 和 hashcode() 方法会自动实现,toString() 将返回这个类实例包含的所有字段的值,最重要的是,x() 和 y() 将分别返回 x 和 y 的值。想想你之前写过的 POJO 类,并想象一下用 record 类来代替它们会怎样。是不是好看多了?省了多少事了?
除此之外,record 类是 final 和不可变的——不能被继承,并且类实例一旦被创建,它的字段就不能被修改。你可以在 record 类中声明方法,包括非静态方法和静态方法:
public record Coord(int x, int y) {
public boolean isCenter() {
return x() == 0 && y() == 0;
总结
无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。
最后我整理了一些面试真题资料,技术知识点剖析教程,还有和广大同仁一起交流学习共同进步,还有一些职业经验的分享。
= 0;
总结
无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。
最后我整理了一些面试真题资料,技术知识点剖析教程,还有和广大同仁一起交流学习共同进步,还有一些职业经验的分享。
[外链图片转存中…(img-KreKaTDH-1714566139907)]