JDK17都出来了,你还在用JDK8?

java初学者

共 3382字,需浏览 7分钟

 ·

2022-01-11 18:16

JDK17的一些新特性

本文旨在介绍一些JDK17的新特性,同时限于篇幅,本文仅列举其中一些差异,而不是全部差异;


PS: JDK17是Java的一个LTS版本(长期支持版本),可以放心迁移过来;

instanceof

JDK8中的语法:

Object o = something;
if (o instanceof String) {
String str = (String)o;
// do something
}

在JDK17中我们可以这样写:

Object o = something;
if (o instanceof String str) {
// do something, 注意上边String后边跟了一个str,相当于把o强转为String同时使用变量名str引用,我们后续可以直接使用str而不用再加一层强转了
}

switch

普通switch

如果switch中只有一条语句时,JDK8中的语法:

String str = something;
switch (str) {
case "123":
System.out.println(str);
break;
case "456":
System.out.println(str);
break;
}

可以看出每个case后边都需要一个 break ,否则会穿透到后边的 case 语句;

JDK17中的语法:

String str = something;
switch (str) {
case "123" -> System.out.println(str);
case "456" -> System.out.println(str);
default -> System.out.println(str);
}

switch的模式匹配

JDK8中的语法:

Object o = something;
if (o instanceof String) {
String str = (String)o;
// do something
} else if (o instanceof Integer) {
Integer integer = (Integer)o;
// do something
}

在JDK17中我们可以这样写(case语句也可以展开,这里为了省事就用了这种写法):

Object o = something;

switch (o) {
case Integer i -> System.out.println(i);
case String str -> System.out.println(str);
default -> System.out.println(o);
}

null值处理

传统(JDK8)switch语句需要提前判null,否则会抛出NPE:

String str = something;
if (str == null) {
// do something
return;
}
switch (str) {
case "123":
System.out.println(str);
break;
case "456":
System.out.println(str);
break;
}

JDK17中无需判空,可以直接 case null :

String str = something;
switch (str) {
case null -> System.out.println("null");
case "123" -> System.out.println(str);
case "456" -> System.out.println(str);
default -> System.out.println(str);
}

复杂条件的case优化:

对于以下代码:

class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }

static void testTriangle(Shape s) {
switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {
System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}

可以优化为:

class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }

static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) ->
System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}

密封类(sealed Class)

在JDK8中,如果我们一个类只想要只想要指定的子类(我们自己编写的类)实现,而不希望其他依赖方自己实现(这种场景在框架编写中很常见),我们通常的方法是将构造器设置为私有的,然后使用 静态内部类来继承该类,或者将构造器设置为package访问级别的,然后在同一个包中编写类来继承;这两种方式虽然都能实现我们的目标(在某些场景也能被打破,例如用户自己编写了一个同名包,然 后就能在包中继续继承该类了),但是都不是太优雅,在我们升级JDK17后该问题也将被解决,JDK17中引入了一个新的关键字 sealed 用来修饰我们不想要其他人私自继承的类(或者接口),然后使用 permits 关键字指定都有那些类可以继承本类,用法如下:

public abstract sealed class TestA permits TestB {

}

public class TestB extends TestA {

}

这里我们使用 sealed 关键字声明 TestA 不能随便被其他类继承,然后使用 permits 声明只有 TestB 才能继承 TestA ,注意,这里 TestB 和 TestA 必须在同一个包中,如 果不在同一个包中,那么 permits 关键字后的 TestB 必须带包名(例如com.JoeKerouac.TestB);


联系我

  • 作者微信:JoeKerouac

  • 微信公众号(文章会第一时间更新到公众号):代码深度研究院

  • GitHub:https://github.com/JoeKerouac

参考文献

  • jdk17完整发布变更说明文档(注:截止文章发布时该地址仍有效,后续JDK继续升级,JDK17被归档后该地址可能无效):https://jdk.java.net/17/release-notes


浏览 23
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报