簡體   English   中英

'if' 語句末尾的分號

[英]Semicolon at end of 'if' statement

今天找了半個小時的bug,發現可以在if語句后加分號代替代碼,像這樣:

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

這基本上意味着無論a是否等於b都會執行這些操作,並且if語句沒有任何意義。 為什么Java不給我一個錯誤? 在任何情況下這會有用嗎?

為什么會發生?

Java 語言規范說:

空聲明

空語句什么也不做。

 EmptyStatement: ;

執行空語句總是正常完成

它本質上意味着如果 a==b,您要執行空語句

if(a == b);

你該怎么辦:

這個問題有兩種主要的解決方案:

  1. 您可以通過在if{}使用代碼格式化程序和周圍內容來避免空語句的問題。 通過這樣做,您的空語句將更具可讀性。

     if(a == b){ ; }
  2. 您還可以檢查用於靜態代碼分析的工具,例如:

    他們可以立即突出顯示諸如此類的問題。

我建議結合這兩種解決方案。

在任何情況下這會有用嗎?

有用? 比如“讓你的代碼更干凈、更清晰、更快、更易於維護”? 一點也不。 這很可能是糟糕的、令人困惑的代碼

但這不一定是良性的 由於導致副作用的方法,這樣的語句可以執行操作和/或更改狀態,並且可選地評估由於操作符的短路而導致的這些方法。

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

這里, a()b()可能會做某事,而b()只會在a()為真時執行。

至於為什么,我認為答案很簡單,偏離定義的、預期的行為(例如while(reader.read());類的語句)比開發人員編寫錯誤代碼的替代方案更糟糕。

編寫糟糕的代碼總是可能的。 重申一下,這幾乎在任何情況下都是糟糕的代碼。

一個可能的用例:

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

不好,但有可能。

不過,我確實認為 Java 規范應該禁止空的if

如果您使用的是 Eclipse,您可以讓它警告您這些語句:

Java->編譯器->錯誤/警告

如果使用if語句,則if后的第一條語句將在條件為真時執行。 如果在if之后有一個塊(帶花括號),則它計入整個塊。 如果沒有塊,它只計算一個語句。 單個分號是一個空語句。 你也可以從你的例子中編寫代碼,如下所示:

if(a==b) {
    ;
}

這是一個古老的遺留物,當時有更多的語法糖來區分表達式和語句。

基本上,逗號用作列表項分隔符,因此分號用作“語句列表”分隔符。 缺點是處理列表中的空項目和塊中的空語句。

在項目列表中,Java 使用顯式關鍵字null ,但“空語句”只是一個空行。 允許存在空行是繼承自 C 的傳統的延續。

為什么要這樣做? 特別是當您知道沒有正在執行任何語句時使用if語句:因為某些 if 語句有副作用:

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

是的,這不是最好的例子,但基本上它說從流中讀取一個字節並且什么都不做。 在某些極端情況下可能很有用,但即使這個例子不是最好的,它也說明了意圖。 我們希望在不意外執行任何語句的情況下感受表達式的副作用。

我想不出它有用的場合。 它對於像這樣的循環很有用

 while(do something);

或者

 for(init; do something; something else);

如果您經常在 IDE 中使用代碼格式,這些類型的錯誤就會變得很明顯。 一些 IDE 也強調這是一個可能的錯誤。

我同意你的看法,這對人類沒有任何用處。 我懷疑它在那里是因為它簡化了語言定義; 例如,這意味着在if之后出現的事物與在一段while之后出現的事物相同。

為什么? 這是因為它對編譯器編寫者來說更容易。 您不必在if(cond)之后做一個特殊情況來檢查分號,並且增加了允許的用法

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

盡管允許這樣做實際上是一個糟糕的主意。 允許然后添加一個案例來檢查這個更容易。

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語句確實改變了輸出。 因此,這樣的聲明可能會有所作為。

在這種情況下,這可能是有用的,或者說對程序有影響更好。

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

如果只有一行要執行,您可以使用不帶{}的 IF 語句,因此使用if(a==b); 你是說如果它們相等,執行和空語句......所以它什么都不做,然后返回到你的正常循環,在 IF 塊之外。

jls 中的一些定義解釋了這一點(第 14 章):

塊是語句

正如此處所述,一個Block是一個StatementWithoutTrailingSubstatement ,而后者又是一個StatementNoShortIf ,它是一個Statement 因此,無論何時需要這些,我們都可以插入一個Block

if 子句

盡管forwhile循環也是如此,但我將使用if語句。 這些規則幾乎相同。 可以在此處找到if-statements的句法描述。

IfThenStatement:
    if ( Expression ) Statement

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

IfThenElseStatementNoShortIf:
    if ( Expression ) StatementNoShortIf else StatementNoShortIf

所以我們可以在這里使用我們的塊。

但為什么它適用於; ?

; 被定義為EmptyStatement ( link ),它也是StatementNoShortIf 因此,在條件代碼段中,例如if-statement和循環,如果需要StatementNoShortIfStatement ,我們可以將Block替換為EmptyStatement

因此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。

我可以想到一個需要空語句的場景(不是用於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

看看這個:

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); 做注意

if 中的分號表示 if 條件的終止,如 java 中一樣; 被視為語句的結束,因此執行 if 之后的語句。

結尾的分號,
如果(a==b); 只需在單行中完成語句,這意味着忽略條件的結果並從下一行繼續執行
這段代碼很有用,另一方面有時會在程序中引入錯誤,例如,

情況1。

一 = 5;
b = 3;
如果(a == b);
prinf("a 和 b 相等");

情況二。

一 = 5;
b = 5;
如果(a == b);
prinf("a 和 b 相等");
會在屏幕上打印相同的輸出...

在為班級進行編程作業時,我正在使用 N x N 網格裝飾品並將隨機裝飾品的特征與上方、下方、左側和右側的特征進行比較,我發現它的一個很好的用途是防止嵌套語句和潛在的邊界例外。 我的目標是最小化代碼並避免嵌套 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 之間做一些操作。

或者,您可以使用異常處理來避免這種語法,但它適用於我的應用程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM