'if'语句结尾的分号


70

今天,在搜索错误半小时之后,我发现可以在if语句后加上分号而不是代码,如下所示:

if(a == b);
// Do stuff

从根本上讲,这意味着无论是否a相等,这些工作都将完成b,并且该if语句毫无意义。Java为什么不给我一个错误?有什么情况会有用吗?


1
看起来像是无操作,即如果a与b相同,则什么也不做;您可以在那里添加Javadoc,但我想不出其他用途
Scorpion

12
不,这是没有用的。为什么?如果我在Java中不了解的每件事都得到一分钱:)
gefei

4
一般规则是分号(;)完成该语句。所以在那之后什么也没发生if
bonCodigo

1
啊哈!这是Python语法的一种错误-带有显示块范围的可视缩进,这使得这种错误不太可能在Python中发生,因为通常,如果if语句中不缩进代码块,则它不在if语句中。
Paddy3118

@gefei:这是没有用的,是真的。但是在某些情况下,这可能会(或用于)影响程序。请看我的回答。
Mukul Goel

Answers:


87

为什么会发生?

Java语言规范说:

空话

空语句不执行任何操作。

EmptyStatement:
    ;

空语句的执行总是正常完成

从本质上讲,这意味着您要在a == b时执行空语句

if(a == b);

你该怎么办:

此问题有两种主要解决方案:

  1. 您可以通过使用代码格式化和周围里面的东西避免空语句的问题if{}。这样,您的空语句将更具可读性。

    if(a == b){
      ;
    }
    
  2. 您还可以检查用于静态代码分析的工具,例如:

    他们可以立即突出显示诸如此类的问题。

我建议结合两种解决方案。


6
即使是使用代码格式化程序的最简单的解决方案,也可以解决此问题。旨在包含在if中的语句将以与if相同的缩进出现。
Patricia Shanahan 2013年

可以,但是我建议同时使用格式化程序和静态代码分析。
Marcin Szymczak

8
您无法通过使用花括号来避免这种情况,因为在封闭括号之后和在开放花括号之前的偶然分号是语法上有效的程序……可能不是您想要的。但是,我同意有关物质的代码可能有助于避免此问题。
AgilePro 2013年

28

有什么情况会有用吗?

有用?如“使代码更清晰,更清晰,更快,更可维护”中所述?一点也不。这很可能是糟糕的,令人困惑的代码

但这不一定是良性的。由于引起副作用的方法,这样的陈述可以执行动作和/或改变状态,并且由于操作员的短路而可选地评估那些方法。

if( a() && b() );

在这里,a()或者b()可能会有所作为,并且b()只有在a()为true时才会执行。

至于为什么,我认为答案很简单,那就是偏离已定义的预期行为(例如诸如之类的语句while(reader.read());)要比开发不良代码的开发人员更糟。

编写错误代码始终是可能的。重申一下,几乎在任何情况下,这都是不好的代码。


9
@gefei-就我而言,这是可怕的风格。
Tim Medora

@Gumbo-我想这if可能表明意图更多。
Tim Medora

2
不,这只会使将来的读者对这是否是错字感到困惑。为什么不只是超级清晰,而只是一点点冗长呢?if(!a()) b();
yshavit

@yshavit-参见我之前的评论,即“这是可怕的风格”。我不会以任何形式使用此构造。
Tim Medora

1
是的,很抱歉,错过了那是您:)
yshavit 2013年

19

一个可能的用例:

if (a==b);
else {
  // Do something
}

不好,但是可能。

不过,我确实认为Java规范应禁止使用empty if


3
这样的代码实际上可以通过考虑所有情况来防止逻辑错误。“如果为真,则不执行任何操作,否则...”将更具可读性,因为您不会因否定错误和“遗漏案件”而感到困惑。如今,大多数编译器都知道这种构造,并且无论如何都会为您求反以提高速度。例如,水星语言强制执行此操作!
tu-Restate Monica-dor duh

2
@tudor我要说的是,即使对于这种用例,也最好这样做if (a==b) { // do nothing } else { doSomething(); },因为更明显的是,无操作是有目的的而不是错字。
yshavit 2013年

@yshavit是的。注释有助于使事情在很多时候变得更加清晰,但这与这种构造不同。此外,if(a == b)之间没有功能上的区别。//不执行任何操作,如果(a == b){/ *不执行操作* /}两者都将通过删除注释和空例并反转条件来优化。
tu-Restate Monica-dor duh,2013年

@tudor对于编译器,是的,对此毫无疑问。但是,让我这样说:如果我看到有人用自己的方式这样做,我会想出“这个人一定以为这样表达条件会更容易。” 如果我看到他们使用分号+ else-braces语法,则将检查VCS日志以确保它不是拼写错误/错误,其他人后来在其中添加了else子句。
yshavit

11

如果您使用的是Eclipse,则可以警告您有关以下语句的信息:

Java->编译器->错误/警告


8

如果使用一条if语句,if则在条件为true时将执行后面的第一条语句。如果在if(花括号)之后有一个块,则该块将计入整个块。如果没有块,则仅计入一条语句。单个分号是一个空语句。您还可以像这样从示例中编写代码:

if(a==b) {
    ;
}

+1,最简单明了的解释,说明为什么不采用这种知识。
sorpigal

7

自从存在更多语法糖来区分表达式和语句的时代以来,这是一个古老的遗留物。

基本上,逗号用作列表项分隔符,因此分号用作“语句列表”分隔符。缺点是处理列表中的空项目和块中的空语句。

在项目列表中,Java使用显式关键字null,但是“空语句”只是一个空行。允许存在空行是从C继承的传统的保留。

为什么呢 if当您知道不执行任何语句时尤其如此:因为某些if语句具有副作用:

 int c;
 if ((c = in.read()) != -1);

是的,这不是最好的例子,但是基本上它说从流中读取一个字节,什么也不做。在某些情况下可能很有用,但是即使这个例子不是最好的,它也可以说明目的。我们希望在不意外执行任何语句的情况下感受表达式的副作用。


5

我想不出有用的场合。对于像这样的循环很有用

 while(do something);

要么

 for(init; do something; something else);

如果您在IDE中定期使用代码格式,则这些错误很明显。一些IDE也将其突出显示为可能的错误。


4

我同意您的观点,对于人类来说这没有任何用处。我怀疑它在那里,因为它简化了语言定义。例如,这意味着a之后的事物与ife之后的事物相同while


3

为什么?这是因为它对编译器编写者来说更容易。您不必在以后进行分号检查时进行特殊处理,if(cond)并且可以使用

if (cond && maybeFunc())
    ;// Code here I want to ignore

即使允许这样做实际上是一个可怕的主意。允许再添加一个案例来检查这一点比较容易。


+1,但不需要使用示例。如您所展示的,它可以被使用,但是它并不是组织该代码的最佳方法。这很丑陋,但是没有理由要特殊情况以拒绝它-至少是从编译器的POV中拒绝。从一个狡猾的POV ...
jmoreno,

2

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定义的方式。


很好,如果没有其他例子,有趣的是这里没有人提及。+1
Mordechai

2

仅供参考,关于可用性以及如果有这样的声明,它将产生或可能产生什么变化

考虑如下代码。

int a = 10;
if ((a = 50) == 50);

System.out.println("Value of a = " + a);

显然,在这种情况下 if语句确实更改了输出。因此,这样的声明可以有所作为。

在这种情况下,这可能有用或更好地说会对程序产生影响。


1
if(a==b)
    println("a equals b");

您可以使用IF语句而无需{}仅执行一行,因此使用IF语句if(a==b);可以说它们是否相等,execute和empty语句...因此它将什么都不做,然后返回到外部的常规循环IF块的


7
println("a now equals b");
用户

1

jls的一些定义对此进行了解释(第14章):

块是陈述

如前所述这里,一个Block是一个StatementWithoutTrailingSubstatement,这又是一个StatementNoShortIf,这是一个Statement。因此,在任何需要这些信息的地方,我们都可以插入Block

如果子句

尽管forwhile-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和循环,我们可以更换一个BlockEmptyStatement,如果一个StatementNoShortIfStatement要求。

这样if(Expression)EmptyStatement工作。

为什么这没有给出错误?

很简单:如果发现无效的语法,java会给出一个错误。但是if(Expression)EmptyStatement是完全有效的语法。相反javac,如果启动带有适当参数的警告。可以禁用/启用的警告的完整列表列出了empty为此目的的警告名称。所以用-Xlint:all或编译-Xlint:empty会对此产生警告。

您的IDE也应该具有启用这种警告的选项。有关日食,请参阅@nullptr的答案。在IntelliJ中,您可以按Ctrl + Shift + A,进入empty body搜索字段并启用警告(在图像中标记)

IntelliJ启用空体警告

这甚至是做什么用的?

老实说,从简约的角度来看,它没有太多用处。通常,有一种无需“不执行任何操作”命令即可完成工作的方法。这是个人喜好问题,是否愿意使用

if( a() && b() );

要么

if( a() ) b();

EmptyStatement使用的其他情况下也是如此。在此主题上要考虑的重要一点是代码的可读性。在某些情况下,使用no-op可使代码更具可读性。另一方面,在某些情况下,使用EmptyStatement-变得很难理解代码-上面的示例将计入后来的IMO。


0


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相等”);
会在屏幕上打印相同的输出...


“此代码很有用” <-忽略条件结果如何有用?
vegemite4me 2013年

是的,在if-elseif层次结构中,如果我们需要忽略某些条件的结果,则可以使用它。例如
Narayan Bhandari 2014年

0

我可以想到一个需要空语句的情况(不是为了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

0

看看这个:

int a,b,c = 0;
if(a == b){
   c =1;
} 
System.out.print(c);//1

因此,您可以这样编写:

if (a == b)c=1;

但是,如果这段代码是这样的:

int a,b,c=0;
if (a != b){
}
if (a == b ){
  c =1;
}

您可以这样写:

if(a != b);
if(a == b )c=1;

这样,你就会知道 if(a != b);做提



-2

在为班级编程工作时,我正在使用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之间进行一些操作。

另外,您可以使用异常处理来避免使用这种语法,但是对于我的应用程序,它可以正常工作。


1
if(row != 0) method (grid[row][col], grid[row-1][col]);不使用空if语句将具有相同的效果。
intcreator 17-6-27
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.