为什么是“new String();” 一个声明但是“new int[0];” 不是?

Jas*_*n V 5 java syntax

我只是随机尝试查看是否new String();可以编译并且它确实可以编译(因为根据 Oracle 的 Java 文档“表达式、语句和块”,有效的语句类型之一是“对象创建”),

但是,new int[0];给了我一个“不是声明”的错误。

这有什么问题?我不是在创建一个数组对象new int[0]吗?

编辑:

为了澄清这个问题,以下代码:

class Test {
    void foo() {
        new int[0];
        new String();
    }
}
Run Code Online (Sandbox Code Playgroud)

在 上导致编译器错误new int[0];,而new String();其本身没有问题。为什么一个不可接受而另一个很好?

rzw*_*oot 6

原因是一个有点过度设计的规范。

表达式不是有效语句背后的想法是它们什么也做不了。5 + 2;什么都不做。你必须把它赋值给某个东西,或者把它传递给某个东西,否则为什么要写它?

但是,也有例外:表达式本身会(或可能会)产生副作用。例如,虽然这是非法的:

void foo(int a) {
    a + 1;
}
Run Code Online (Sandbox Code Playgroud)

这不是:

void foo(int a) {
    a++;
}
Run Code Online (Sandbox Code Playgroud)

那是因为,就其本身而言,a++它并不是完全无用的,它实际上会改变事物(通过这样做来修改 a)。实际上,a + 1如果自行产生价值的行为导致其他事情发生,“忽略价值”(您在第一个片段中什么都不做)是可以接受的:毕竟,也许这就是您一直以来的样子。

出于这个原因,调用方法也是一个合法的表达式语句,事实上,调用方法(即使是不返回的方法void)而忽略返回值是很常见的。对于 void 方法,它甚至是调用它们的唯一合法方式。

构造函数在技术上是方法,可能有副作用。如果这种方法是极不可能的,并且代码风格非常糟糕:

void doStuff() {
    new Something();
}
Run Code Online (Sandbox Code Playgroud)

是“明智”的代码,但它可能在理论上可以写的,不好的,因为它可能是:在的构造函数Something类可能会做一些有用的东西,也许这就是你要在这里做的:作出这样的构造来看,做有用的事,和然后取出创建的对象并立即将其扔进垃圾箱。很奇怪,但是,好吧。你是程序员。

对比:

new Something[10];
Run Code Online (Sandbox Code Playgroud)

这是不同的:编译器知道数组“构造函数”的作用。它所做的没有任何用处——它创建一个对象并返回对对象的引用,这就是所有发生的事情。如果您立即将引用扔进垃圾箱,那么整个操作完全是在浪费时间,而且您肯定不打算对这种奇怪的语句做任何有用的事情,因此编译器设计者认为最好直接禁止你从写它。

这个“哦,亲爱的,代码没有意义,所以我不会编译它”是非常有限的,而且主要是原始编译器规范的一个过时的方面;它从未更新过,这不是相信代码合理的好方法;有各种各样的 linter 工具可以更进一步地找到你的代码,但不可能是正确的,所以如果你关心这类事情,投资学习这些。

尽管如此,java 1.0 规范已经包含了这些东西,并且没有特别好的理由放弃 java 规范的这方面,因此,它仍然存在,并且构造一个新数组不是一个有效的 ExpressionStatement。

正如JLS §14.8所述,具体而言, aClassInstanceCreationExpression在有效表达式语句列表中。单击该词以链接到 的定义,ClassInstanceCreationExpression您会发现它特指调用构造函数,而不是数组构造。

因此,JLS 是特定的并且需要这种行为。javac 只是遵循规范。