为什么 "new String();" 是一个声明而 "new int[0];" 不是?
Why is "new String();" a statement but "new int[0];" not?
我只是随机尝试查看 new String();
是否会编译,它确实编译了(因为根据 Oracle 的 Java 关于“表达式、语句和块”的文档,一种有效的语句类型是“对象创建"),
但是,new int[0];
给我一个“不是声明”的错误。
这有什么问题吗?我不是用 new int[0]
创建数组对象吗?
编辑:
为了澄清这个问题,代码如下:
class Test {
void foo() {
new int[0];
new String();
}
}
在 new int[0];
上导致编译器错误,而 new String();
本身 是 没问题。为什么一个不行,一个可以?
原因是规格有些过度设计。
表达式不是有效语句背后的想法是它们什么也做不了。 5 + 2;
自己什么都不做。必须赋值给什么东西,或者传给什么东西,不然为什么要写?
但是也有例外:表达式本身会(或可能会)产生副作用。例如,虽然这是非法的:
void foo(int a) {
a + 1;
}
这不是:
void foo(int a) {
a++;
}
那是因为,就其本身而言,a++
并非完全无用,它实际上改变了一些东西(通过这样做修改了 a)。实际上,如果自行产生价值的行为导致其他事情发生,'ignoring the value'(你在第一个片段中对 a + 1
不做任何事情)是可以接受的:毕竟,也许这就是你所追求的一直以来。
因此,调用方法也是一种合法的表达语句,事实上,调用方法(即使是那些不 return void
的方法)是很常见的,忽略 return 值。对于 void 方法,这是调用它们的唯一合法方式,甚至。
构造函数在技术上是方法,可能有副作用。如果这种方法:
,那是极不可能的,而且代码风格很糟糕
void doStuff() {
new Something();
}
是 'sensible' 代码,但理论上 可以 编写,尽管它可能很糟糕:Something
[=72= 的构造函数] 可能会做一些有用的事情,也许这就是你想在这里做的所有事情:创建构造函数 运行,做有用的事情,然后获取创建的对象并立即将其扔进垃圾箱。很奇怪,但是,好吧。你是程序员。
对比:
new Something[10];
这是不同的:编译器知道数组'constructor'做什么。它所做的是 没有任何用处 - 它创建一个对象并 return 引用该对象,这就是 all 发生的事情.如果您随后立即将引用扔进垃圾箱,那么整个操作完全是在浪费时间,而且您肯定不想对这种奇怪的语句做任何有用的事情,因此编译器设计者认为最好直接禁止你别写了。
这个 'oh dear that code makes no sense therefore I shall not compile it' 非常 有限,并且大部分是原始编译器规范的过时方面;它从未更新过,这不是相信代码合理的好方法;市面上有各种各样的 linter 工具,它们可以大大帮助您找到根本不正确的代码,所以如果您关心这类事情,请投资学习这些工具。
然而,java 1.0 规范已经包含了这些东西,没有特别好的理由放弃 java 规范的这方面,因此,它仍然存在,并构建一个新数组不是有效的 ExpressionStatement。
如 JLS §14.8 所述,具体来说,ClassInstanceCreationExpression
在有效表达式语句列表中。点击那个词link到ClassInstanceCreationExpression
的定义,你会发现它特指调用构造函数,不是数组构造。
因此,JLS 是特定的,需要 这种行为。 javac 只是遵循规范。
我只是随机尝试查看 new String();
是否会编译,它确实编译了(因为根据 Oracle 的 Java 关于“表达式、语句和块”的文档,一种有效的语句类型是“对象创建"),
但是,new int[0];
给我一个“不是声明”的错误。
这有什么问题吗?我不是用 new int[0]
创建数组对象吗?
编辑:
为了澄清这个问题,代码如下:
class Test {
void foo() {
new int[0];
new String();
}
}
在 new int[0];
上导致编译器错误,而 new String();
本身 是 没问题。为什么一个不行,一个可以?
原因是规格有些过度设计。
表达式不是有效语句背后的想法是它们什么也做不了。 5 + 2;
自己什么都不做。必须赋值给什么东西,或者传给什么东西,不然为什么要写?
但是也有例外:表达式本身会(或可能会)产生副作用。例如,虽然这是非法的:
void foo(int a) {
a + 1;
}
这不是:
void foo(int a) {
a++;
}
那是因为,就其本身而言,a++
并非完全无用,它实际上改变了一些东西(通过这样做修改了 a)。实际上,如果自行产生价值的行为导致其他事情发生,'ignoring the value'(你在第一个片段中对 a + 1
不做任何事情)是可以接受的:毕竟,也许这就是你所追求的一直以来。
因此,调用方法也是一种合法的表达语句,事实上,调用方法(即使是那些不 return void
的方法)是很常见的,忽略 return 值。对于 void 方法,这是调用它们的唯一合法方式,甚至。
构造函数在技术上是方法,可能有副作用。如果这种方法:
,那是极不可能的,而且代码风格很糟糕void doStuff() {
new Something();
}
是 'sensible' 代码,但理论上 可以 编写,尽管它可能很糟糕:Something
[=72= 的构造函数] 可能会做一些有用的事情,也许这就是你想在这里做的所有事情:创建构造函数 运行,做有用的事情,然后获取创建的对象并立即将其扔进垃圾箱。很奇怪,但是,好吧。你是程序员。
对比:
new Something[10];
这是不同的:编译器知道数组'constructor'做什么。它所做的是 没有任何用处 - 它创建一个对象并 return 引用该对象,这就是 all 发生的事情.如果您随后立即将引用扔进垃圾箱,那么整个操作完全是在浪费时间,而且您肯定不想对这种奇怪的语句做任何有用的事情,因此编译器设计者认为最好直接禁止你别写了。
这个 'oh dear that code makes no sense therefore I shall not compile it' 非常 有限,并且大部分是原始编译器规范的过时方面;它从未更新过,这不是相信代码合理的好方法;市面上有各种各样的 linter 工具,它们可以大大帮助您找到根本不正确的代码,所以如果您关心这类事情,请投资学习这些工具。
然而,java 1.0 规范已经包含了这些东西,没有特别好的理由放弃 java 规范的这方面,因此,它仍然存在,并构建一个新数组不是有效的 ExpressionStatement。
如 JLS §14.8 所述,具体来说,ClassInstanceCreationExpression
在有效表达式语句列表中。点击那个词link到ClassInstanceCreationExpression
的定义,你会发现它特指调用构造函数,不是数组构造。
因此,JLS 是特定的,需要 这种行为。 javac 只是遵循规范。