今天,在搜索错误半小时之后,我发现可以在if语句后加上分号而不是代码,如下所示:
if(a == b);
// Do stuff
从根本上讲,这意味着无论是否a
相等,这些工作都将完成b
,并且该if
语句毫无意义。Java为什么不给我一个错误?有什么情况会有用吗?
今天,在搜索错误半小时之后,我发现可以在if语句后加上分号而不是代码,如下所示:
if(a == b);
// Do stuff
从根本上讲,这意味着无论是否a
相等,这些工作都将完成b
,并且该if
语句毫无意义。Java为什么不给我一个错误?有什么情况会有用吗?
if
Answers:
Java语言规范说:
空话
空语句不执行任何操作。
EmptyStatement: ;
空语句的执行总是正常完成
从本质上讲,这意味着您要在a == b时执行空语句
if(a == b);
此问题有两种主要解决方案:
您可以通过使用代码格式化和周围里面的东西避免空语句的问题if
有{
和}
。这样,您的空语句将更具可读性。
if(a == b){
;
}
您还可以检查用于静态代码分析的工具,例如:
他们可以立即突出显示诸如此类的问题。
我建议结合两种解决方案。
有什么情况会有用吗?
有用?如“使代码更清晰,更清晰,更快,更可维护”中所述?一点也不。这很可能是糟糕的,令人困惑的代码。
但这不一定是良性的。由于引起副作用的方法,这样的陈述可以执行动作和/或改变状态,并且由于操作员的短路而可选地评估那些方法。
if( a() && b() );
在这里,a()
或者b()
可能会有所作为,并且b()
只有在a()
为true时才会执行。
至于为什么,我认为答案很简单,那就是偏离已定义的预期行为(例如诸如之类的语句while(reader.read());
)要比开发不良代码的开发人员更糟。
编写错误代码始终是可能的。重申一下,几乎在任何情况下,这都是不好的代码。
if
可能表明意图更多。
if(!a()) b();
一个可能的用例:
if (a==b);
else {
// Do something
}
不好,但是可能。
不过,我确实认为Java规范应禁止使用empty if
。
if (a==b) { // do nothing } else { doSomething(); }
,因为更明显的是,无操作是有目的的而不是错字。
自从存在更多语法糖来区分表达式和语句的时代以来,这是一个古老的遗留物。
基本上,逗号用作列表项分隔符,因此分号用作“语句列表”分隔符。缺点是处理列表中的空项目和块中的空语句。
在项目列表中,Java使用显式关键字null
,但是“空语句”只是一个空行。允许存在空行是从C继承的传统的保留。
为什么呢 if
当您知道不执行任何语句时尤其如此:因为某些if语句具有副作用:
int c;
if ((c = in.read()) != -1);
是的,这不是最好的例子,但是基本上它说从流中读取一个字节,什么也不做。在某些情况下可能很有用,但是即使这个例子不是最好的,它也可以说明目的。我们希望在不意外执行任何语句的情况下感受表达式的副作用。
Java允许在任何允许语句块的地方使用空块。我确定将所有块作为通用规则可以简化编译器。
我同意这主要是导致难以发现的错误的原因。我总是在块周围使用大括号,即使只有一条语句,但Java允许您在任何时候使用大括号创建一个块,因此使用大括号无法使您免于命运。例如,我曾经浪费4个小时来尝试查找以下内容:
while (condition);
{
statement;
statement;
}
第一行末尾的分号是一个错字,偶然使while循环的语句块为空。因为语法是有效的,所以程序已编译并可以正常运行,只是不是我想要的那样。这是真的很难找到。
我可以想到一种情况,允许您有空块非常好,这是这样的:
if (condition1) {
do_action_1();
}
else if (condition2) {
//nothing really to do in this case
}
else if (condition3) {
do_action2();
}
else {
do_action3();
}
在上面的示例中,您希望能够分离出各种条件。请记住,这些条件可能是重叠的,因此并非总是可以重新排列顺序。如果条件之一真的不需要做任何事情,那么Java允许您有一个空块就很好了。否则,当您确实不希望做任何事情时,该语言将需要某种形式的“ noop”方法来使用。
我个人更喜欢显式的“ noop”语句-但这不是Java定义的方式。
仅供参考,关于可用性以及如果有这样的声明,它将产生或可能产生什么变化
考虑如下代码。
int a = 10;
if ((a = 50) == 50);
System.out.println("Value of a = " + a);
显然,在这种情况下 if
语句确实更改了输出。因此,这样的声明可以有所作为。
在这种情况下,这可能有用或更好地说会对程序产生影响。
jls的一些定义对此进行了解释(第14章):
如前所述这里,一个Block
是一个StatementWithoutTrailingSubstatement
,这又是一个StatementNoShortIf
,这是一个Statement
。因此,在任何需要这些信息的地方,我们都可以插入Block
。
尽管for
和while
-loops也是如此,但我将使用if
-statements。这些规则几乎相同。的语法描述if-statements
可以在这里找到。
IfThenStatement:
if ( Expression ) Statement
IfThenElseStatement:
if ( Expression ) StatementNoShortIf else Statement
IfThenElseStatementNoShortIf:
if ( Expression ) StatementNoShortIf else StatementNoShortIf
所以我们可以在这里使用我们的块。
;
被定义为EmptyStatement
(链接),也就是StatementNoShortIf
。所以在有条件的代码块,像if-statement
和循环,我们可以更换一个Block
用EmptyStatement
,如果一个StatementNoShortIf
或Statement
要求。
这样if(Expression)EmptyStatement
工作。
很简单:如果发现无效的语法,java会给出一个错误。但是if(Expression)EmptyStatement
是完全有效的语法。相反javac
,如果启动带有适当参数的警告。可以禁用/启用的警告的完整列表列出了empty
为此目的的警告名称。所以用-Xlint:all
或编译-Xlint:empty
会对此产生警告。
您的IDE也应该具有启用这种警告的选项。有关日食,请参阅@nullptr的答案。在IntelliJ中,您可以按Ctrl + Shift + A
,进入empty body
搜索字段并启用警告(在图像中标记)
老实说,从简约的角度来看,它没有太多用处。通常,有一种无需“不执行任何操作”命令即可完成工作的方法。这是个人喜好问题,是否愿意使用
if( a() && b() );
要么
if( a() ) b();
在EmptyStatement
使用的其他情况下也是如此。在此主题上要考虑的重要一点是代码的可读性。在某些情况下,使用no-op可使代码更具可读性。另一方面,在某些情况下,使用EmptyStatement
-变得很难理解代码-上面的示例将计入后来的IMO。
在
if(a == b)末尾的分号;只需在单行中完成语句,这意味着忽略条件的结果并从下一行继续执行。
此代码很有用,另一方面有时会在程序中引入错误,例如
情况1。a
= 5;
b = 3;
if(a == b);
prinf(“ a和b相等”);
情况2.
a = 5;
b = 5;
if(a == b);
prinf(“ a和b相等”);
会在屏幕上打印相同的输出...
我可以想到一个需要空语句的情况(不是为了if
条件而是为了while
循环)。
当程序只希望用户明确确认继续。当用户确认后的工作依赖于其他一些事项并且用户希望控制何时进行时,可能需要执行此操作。
System.out.println("Enter Y to proceed. Waiting...");
System.out.println("");
while(!(new Scanner(System.in).next().equalsIgnoreCase("Y")));
System.out.println("Proceeding...");
// do the work here
if中的分号表示将java中的if条件终止;
视为一条语句的末尾,因此执行if之后的语句。
在为班级编程工作时,我正在使用N by N的doodad网格,并将随机doodad的特征与上,下,左,右的特征进行比较,我发现可以很好地使用此功能来防止嵌套语句和潜在的边界例外。我的目标是尽量减少代码并避免嵌套if语句。
if (row == 0);
else (method (grid[row][col], grid[row-1][col]));
if (row == N-1);
else (method (grid[row][col], grid[row+1][col]));
if (col == 0);
else (method (grid[row][col], grid[row][col-1]));
if (col == N-1);<br>
else (method (grid[row][col], grid[row][col+1]));
在method(Doodad a, Doodad b)
a和b之间进行一些操作。
另外,您可以使用异常处理来避免使用这种语法,但是对于我的应用程序,它可以正常工作。
if(row != 0) method (grid[row][col], grid[row-1][col]);
不使用空if
语句将具有相同的效果。