分号在“if”语句结尾
今天,在search一个bug的半小时后,我发现可以在if语句后面加一个分号而不是代码,如下所示:
if(a == b); // Do stuff
这基本上意味着这些东西将会被完成,无论是否等于b,if语句都没有任何意义。 为什么Java不给我一个错误? 有没有什么情况会有用?
为什么会发生?
Java语言规范说:
空的声明
一个空的陈述什么都不做。
EmptyStatement: ;
空语句的执行总是正常完成
它基本上意味着你要执行空的语句,如果一个== b
if(a == b);
你该怎么办:
这个问题有两个主要的解决scheme:
-
if
使用{
和}
可以通过使用代码格式化程序和周围的内容来避免空语句的问题。 通过这样做你的空白语句将更加可读。if(a == b){ ; }
-
您还可以检查用于静态代码分析的工具,例如:
- FindBugs的
- Checkstyle的
- PMD
他们可以即时突出像这样的问题。
我会build议结合这两种解决scheme。
有没有什么情况会有用?
有用? 如“让你的代码更干净,更清晰,更快,更易于维护”? 一点也不。 这很可能是糟糕的,令人困惑的代码 。
但这不一定是良性的 。 这样的陈述可以由于引起副作用的方法来执行动作和/或改变状态,并且可选地由于操作员的短路而评估那些方法。
if( a() && b() );
在这里, a()
或b()
可以做某事,而b()
只有在a()
为真时才会执行。
至于为什么 ,我认为答案只不过是偏离已定义的预期行为(比如while(reader.read());
)而不是开发人员编写错误代码的替代方法。
编写错误的代码总是可能的。 只是重申,几乎在任何情况下这都是不好的代码。
一个可能的用例:
if (a==b); else { // Do something }
不好,但可能。
不过,我认为Java规范应该禁止一个空的if
。
如果你使用的是Eclipse,你可以使它警告你:
如果使用if
语句, if
语句之后的第一个语句将在条件为真时执行。 如果if
(花括号)之后有一个块,则表示整个块。 如果没有块,则只计算一个语句。 一个分号是一个空的语句。 你也可以像这样写代码:
if(a==b) { ; }
从语法上有更多的糖来区分表述和陈述的时代,这是一个老的剩余。
基本上,逗号被用作列表项分隔符,所以分号被用作“语句列表”分隔符。 不足之处在于处理列表中的空项目和空块语句。
在项目列表中,Java使用显式关键字null
,但“空白语句”只是一个空行。 允许空行的存在是从Cinheritance的传统的保留。
为什么呢? 特别是当你知道没有语句正在被执行的if
语句时:因为一些if语句有副作用:
int c; if ((c = in.read()) != -1);
是的,这不是最好的例子,但基本上它说从stream中读取一个字节,什么都不做。 在某些情况下可能会有用,但即使这个例子不是最好的,它也说明了这个意图。 我们希望在不意外执行任何语句的情况下感受expression式的副作用。
我想不出有用的地方。 对于像这样的循环可能会有用
while(do something);
要么
for(init; do something; something else);
如果你经常在你的IDE中使用你的代码格式,这些错误就会变得很明显。 一些IDE强调这也是一个可能的错误。
我同意你的观点,对于一个人来说没有任何有用的目的。 我怀疑它在那里,因为它简化了语言的定义; 那就意味着后来的东西和后来的东西是一样的。
为什么? 这是因为编译器编写者更容易。 if(cond)
之后,你不必做一个特殊的情况来检查分号,并且有一个允许的附加用法
if (cond && maybeFunc()) ;// Code here I want to ignore
尽pipe这是一个可怕的主意。 容易,然后添加一个案件来检查这一点。
Java允许一个空的块在任何地方允许一个语句块。 我确信这是所有块的通用规则简化了编译器。
我同意这主要是很难find的错误的原因。 即使只有一个语句,我总是在块周围使用大括号,但是Java允许您在任何时候使用大括号来创build块,所以使用大括号不能免除这个命运。 例如,我曾经浪费了4个小时试图find这样的东西:
while (condition); { statement; statement; }
第一行末尾的分号是一个拼写错误,意外使while循环的语句块为空。 由于语法是有效的程序编译和运行良好,只是不是我想要的方式。 这真的很难find。
我可以想到一个情况,允许你有空块是非常好的 ,这是这样的:
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
语句确实会改变输出。 所以这样的陈述可以有所作为。
在这种情况下,对计划产生影响可能是有用的或者更好的。
if(a==b) println("a equals b");
如果只有一行被执行,则可以使用不带{}
的IF语句,所以通过使用if(a==b);
你是在说他们是否平等,执行和清空语句…所以它什么也不做,然后返回到IF块之外的正常循环。
jls的一些定义解释了这一点(第14章):
块是语句
正如这里所说的, Block
是一个没有StatementWithoutTrailingSubstatement
,而它是一个StatementNoShortIf
,它是一个Statement
。 因此,凡是这些都是必需的,我们可以插入一个Block
。
if子句
虽然这同样适用for
while
循环,但我会使用if
语句。 这些规则几乎是一样的。 if-statements
的语法描述可以在这里find。
IfThenStatement: if ( Expression ) Statement IfThenElseStatement: if ( Expression ) StatementNoShortIf else Statement IfThenElseStatementNoShortIf: if ( Expression ) StatementNoShortIf else StatementNoShortIf
所以我们可以在这里使用我们的块。
但是为什么它会起作用; ?
;
被定义为EmptyStatement
( 链接 ),这也是一个StatementNoShortIf
。 因此,在if-statement
和循环等条件代码段中,如果需要StatementNoShortIf
或Statement
,我们可以用EmptyStatement
代替Block
。
因此, if(Expression)EmptyStatement
工作。
为什么不给这个错误?
很简单:如果发现无效的语法,java会给出一个错误。 但if(Expression)EmptyStatement
是完全有效的语法。 相反,如果使用正确的参数启动, javac
会发出警告。 可以禁用/启用的完整警告列表列出了警告名称为empty
的目的。 所以用-Xlint:all
或-Xlint:empty
编译将会产生一个警告。
您的IDE应该有一个选项来启用这种警告。 对于日食,请参阅@ nullptr的答案 。 在IntelliJ中,你可以按Ctrl + Shift + A
,在search框中inputempty body
,并启用警告(在图像中标记)
这甚至用了什么?
说实话,从简约的angular度来看,没有多less用处。 通常有一种方法可以在没有“无所事事”的情况下完成任务。 这是一个个人喜好的问题,不pipe你是否使用
if( a() && b() );
要么
if( a() ) b();
其他情况也适用于使用EmptyStatement
情况。 关于这个话题需要考虑的重要一点是代码的可读性。 在有些情况下,通过使用no-op代码变得更可读。 另一方面,有些情况下,代码变得相当难以理解使用EmptyStatement
– 上面的例子将计入到后来的IMO。
分号结束时,
如果(A == B); 只需简单地完成单行中的语句即意味着忽略条件的结果并继续执行下一行
这个代码是有用的,另一方面有时在程序中引入bug,例如,
情况1。
a = 5;
b = 3;
如果(a == b);
prinf(“a和b是平等的”);
情况2。
a = 5;
b = 5;
如果(a == b);
prinf(“a和b是平等的”);
将在屏幕上打印相同的输出…
我可以想象一个场景,需要一个空的语句(不是为条件,而是为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
当我正在为一个类的编程任务进行工作时,我正在使用一个N×N的装饰网格,并将随机装饰的特征与上面,下面,左边和右边的特征进行比较,我发现这很好地用来防止嵌套语句和潜在的边界例外。 我的目标是尽量减less代码,并避免嵌套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之间进行一些操作。
或者,你可以使用exception处理来避免这种语法,但它适用于我的应用程序。