为什么 instanceof 模式匹配需要标识符?

Why is an identifier required for instanceof pattern matching?

在Java的instanceof模式匹配中,使用了一个额外的标识符来缩小类型:

Object o = "test";
if (o instanceof String s) {
    System.out.println(s.length()); // s is of type String
}

为什么有必要? The JEP 似乎没有理由,但我敢肯定这是有原因的。以下内容有哪些不足之处?

Object o = "test";
if (o instanceof String) {
    System.out.println(o.length());
}

TypeScript and Kotlin 在没有其他标识符的情况下做类似的事情。

我猜这是一个向后兼容的东西 - Java 的怪癖通常是 - 但我想不出一个例子来证明这一点。

我唯一能想到的是,有人可能写了类似于第二个示例前模式匹配的东西,并依赖它 not 编译,但这看起来像是理由不充分。

代码“不合理”的地方:

Object o = "test";
if (obj instanceof String) {
    System.out.println(o.length());
}

是不是编译不通过,因为classObject.

没有方法length()

正确的比较代码是:

Object o = "test";
if (obj instanceof String) {
    System.out.println(((String)o).length());
}

Object o = "test";
if (obj instanceof String) {
    String s = (String)o;
    System.out.println(s.length());
}

使用新语法,

if (obj instanceof String s) {

对于

来说是syntactic sugar
if (obj instanceof String) {
    String s = (String)o;

如果 Java 引入了类似“智能 instanceof”的东西,我们可以争辩说这个特性可以在不引入新变量的情况下发挥作用。

但这不是介绍的内容。新功能是 模式匹配 ,这是一个更大的概念,尽管只是在第一步中以最简单的形式实现。这也是一种新的集成方法,而不是在大功能上工作数十年,而是在保持大愿景的同时不断将较小的功能添加到 Java。

JDK-8260244 描述了接下来的步骤之一,这将允许

(给出)

record Point(int x, int y) {}
void printSum(Object o) {
    if (o instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

甚至

(给出)

record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}
static void printXCoordOfUpperLeftPointWithPatterns(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point(var x, var y), var c), var lr)) {
        System.out.println("Upper-left corner: " + x);
    }
}

由于模式匹配包括创建(有时是多个)新变量,仅创建一个包含与已存在变量相同引用的新变量的情况只是一个角落案件。 即使到目前为止已经实施的,也涵盖了比这更多的案例。例如

if(foo.getObject() instanceof List<?> l && l.get(0) instanceof Map<?,?> m
   && m.get("foo") instanceof String s) {
       // use s
}

同样值得注意的是模式变量的范围is complex。如果变量也存在于此范围之外,但类型不同,那就更令人困惑了。

因此,在存在 instanceof 的情况下根据上下文更改变量的类型虽然很诱人,但会导致问题(一些评论还提到了方法重载选择),同时又不适合进入 Java 语言开发人员的实际视野。