簡體   English   中英

為什么我們使用 if, else if 而不是多個 if 塊,如果主體是 return 語句

[英]Why we use if, else if instead of multiple if block if the body is a return statement

我一直習慣於使用 if, else-if 語句而不是多個 if 語句。

例子:

int val = -1;
if (a == b1) {
   return c1;
} else if (a == b2) {
   return c2;
} ...
...
} else {
   return c11;
}

它與示例 2 相比如何:

if (a == b1) {
   return c1;
}
if (a == b2) {
   return c2;
}
....

if (a == b11) {
   return c11;
}

我知道功能方面它們是相同的。 但是如果 else-if 或 not 是最佳實踐嗎? 當我指出他可以以不同的方式構建代碼庫以使其更清晰時,這是由我的一位朋友提出的。 這對我來說已經是很長時間的習慣了,但我從來沒有問過為什么。

if-elseif-else語句一發現正確就停止進行比較。 if-if-if每一次比較。 第一個效率更高。

編輯:評論中指出您在每個if塊中都進行了return 在這些情況下,或者在控制將離開方法(異常)的情況下,執行多個if語句和執行if-elseif-else語句之間沒有區別。

但是,無論如何最好使用if-elseif-else 假設您更改了代碼,以便不在每個if塊中都進行return 然后,為了保持效率,您還必須更改為if-elseif-else習語。 從一開始就使用if-elseif-else可以節省您將來的編輯工作,並且對於閱讀您的代碼的人來說更清晰(通過瀏覽您的代碼來見證我剛剛給您的誤解!)。

b1 == b2的情況呢? (如果a == b1a == b2 ?)

發生這種情況時,一般來說,以下兩段代碼很可能會有不同的行為:

if (a == b1) {
   /* do stuff here, and break out of the test */
} 
else if (a == b2) {
   /* this block is never reached */
} 

和:

if (a == b1) {
   /* do stuff here */
}
if (a == b2) {
   /* do this stuff, as well */
}

如果您想清楚地描述不同情況的功能,請使用if-elseswitch-case進行一項測試

如果您希望針對多種情況使用不同的功能,請使用多個if塊作為單獨的測試

這不是“最佳實踐”的問題,而是定義您是否有一個測試或多個測試。

它們在功能上並不等效。

它在功能上等效的唯一方法是,如果您對 a 的每個可能值執行“if”語句(即:每個可能的 int 值,如 C 中的 limits.h 中所定義;使用 INT_MIN 和 INT_MAX,或在 Java 中等效) )。

else 語句允許您覆蓋所有可能的剩余值,而無需編寫數百萬個“if”語句。

此外,使用 if...else if...else 是更好的編碼實踐,就像在 switch/case 語句中一樣,如果您不提供“默認”case 語句,您的編譯器將警告您。 這可以防止您忽略程序中的無效值。 例如:

double square_root(double x) {
    if(x > 0.0f) {
        return sqrt(x);
    } else if(x == 0.0f) {
        return x;
    } else {
        printf("INVALID VALUE: x must be greater than zero");
        return 0.0f;
    }
}

在這種情況下,您想為 x 的每個可能值鍵入數百萬條 if 語句嗎? 對此感到懷疑 :)

干杯!

這完全取決於您要測試的條件。 在您的示例中,它最終不會有任何區別,但作為最佳實踐,如果您希望最終執行其中一個條件,那么您最好使用 if else

if (x > 1) {
    System.out.println("Hello!");
}else if (x < 1) {
    System.out.println("Bye!");
}

另請注意,如果第一個條件為 TRUE,則根本不會檢查第二個條件,但如果您使用

if (x > 1) {
    System.out.println("Hello!");
}
if (x < 1) {
    System.out.println("Bye!");
}

即使第一個條件為 TRUE,也會檢查第二個條件。 這可能最終由優化器解決,但據我所知,它的行為方式是這樣的。 此外,第一個是要編寫的並且表現得像這樣,因此除非邏輯另有要求,否則它始終是我的最佳選擇。

我更喜歡 if/else 結構,因為與開關一起評估每個變體中問題的所有可能狀態要容易得多。 我發現它更健壯,調試速度更快,尤其是當您在弱類型環境(如 PHP)中進行多個布爾評估時,例如為什么 elseif 不好(為了演示而誇大了):

if(a && (c == d))
{
} elseif ( b && (!d || a))
{
} elseif ( d == a && ( b^2 > c))
{
} else {
}

這個問題有超過 4^2=16 個布爾狀態,這只是為了展示使事情變得更糟的弱類型效應。 不難想象在if ab elseif bc類型的方式中涉及的三狀態變量,三變量問題。

將優化留給編譯器。

在大多數情況下,使用 if-elseif-else 和 switch 語句比 if-if-if 語句更有效(因為它使編譯器更容易創建跳轉/查找表)和更好的實踐,因為它使您的代碼更具可讀性,加上編譯器確保您在開關中包含默認情況。 這個答案以及比較三個不同陳述的這個表格是使用本頁上的其他答案帖子以及類似的 SO 問題的答案合成的。

我傾向於認為,面對代碼更改,使用else if更容易、更健壯。 如果有人要調整函數的控制流並用副作用替換返回或用try-catch替換函數調用,如果所有條件都真正互斥,則else-if將很難失敗。 這在很大程度上取決於您正在使用的確切代碼來做出一般判斷,並且您需要簡潔地考慮可能的權衡。

在每個if分支中都有return語句。

在您的代碼中,您在每個 if 條件中都有return語句。 當你遇到這樣的情況時,有兩種方法可以寫這個。 第一個是您在示例 1 中的編寫方式:

if (a == b1) {
   return c1;
} else if (a == b2) {
   return c2;
} else {
   return c11;
}

另一種如下:

if (a == b1) {
   return c1;
}
if (a == b2) {
   return c2;
}
return c11; // no if or else around this return statement

這兩種編寫代碼的方式是相同的。

您在示例 2 中編寫代碼的方式不會在 C++ 或 Java 中編譯(並且在 C 中是未定義的行為),因為編譯器不知道您已經涵蓋了a所有可能值,因此它認為存在代碼可以在不返回返回值的情況下到達函數末尾的函數路徑。

if (a == b1) {
   return c1;
}
if (a == b2) {
   return c2;
}
...
if (a == b11) {
   return c11;
}
// what if you set a to some value c12?

在每個if分支中沒有return語句。

如果每個if分支中沒有return語句, if只有在以下語句為真時,您的代碼才會在功能上相同:

  1. 你不發生變異的價值a在任何的if分支。
  2. ==是一個等價關系(在數學意義上)並且b1b11都不在同一個等價類中。
  3. ==沒有任何副作用。

進一步澄清第 2 點(以及第 3 點):

  • ==在 C 或 Java 中始終是等價關系,並且永遠不會產生副作用。
  • 在允許您覆蓋==運算符的語言中,例如 C++、Ruby 或 Scala,被覆蓋的==運算符可能不是等價關系,並且可能會產生副作用。 我們當然希望覆蓋==運算符的人足夠理智,可以編寫沒有副作用的等價關系,但不能保證。
  • 在 JavaScript 和某些其他具有松散類型轉換規則的編程語言中,語言中內置了==不可傳遞或不對稱的情況。 (在 Javascript 中, ===是等價關系。)

在性能方面,示例 #1 保證在匹配后不執行任何比較。 編譯器可能會優化 #2 以跳過額外的比較,但不太可能。 在下面的例子中,它可能不能,如果字符串很長,額外的比較並不便宜。

if (strcmp(str, "b1") == 0) {
  ...
}
if (strcmp(str, "b2") == 0) {
  ...
}
if (strcmp(str, "b3") == 0) {
  ...
}

ifelse if與兩個連續的if語句不同。 在第一種情況下,當 CPU 執行第一個if分支時,不會檢查else if 在連續的兩個if語句中,即使第一個if被檢查並采用,如果條件為真,下一個if也會檢查和采用。

我認為這些代碼片段是等效的,原因很簡單,因為您有許多return語句。 如果您只有一個return語句,您將使用這里不必要的else構造。

您的比較依賴於 if 語句的主體從方法返回控制權的事實。 否則,功能會有所不同。

在這種情況下,它們執行相同的功能。 在我看來,后者更容易閱讀和理解,並且是我的選擇。

他們可能會做不同的事情。

如果a等於b1b2 ,則輸入兩個if塊。 在第一個示例中,您只能輸入一個。 我想第一個例子更快,因為編譯器可能必須按順序檢查每個條件,因為某些比較規則可能適用於對象。 它也許可以優化它們......但如果你只想輸入一個,第一種方法更明顯,不太可能導致開發人員錯誤或低效代碼,所以我絕對推薦這樣做。

CanSpice 的回答是正確的。 性能的另一個考慮因素是找出最常出現的條件。 例如,如果 a==b1 只出現 1% 的時間,那么通過首先檢查其他情況可以獲得更好的性能。

Gir Loves Tacos 的回答也不錯。 最佳做法是確保您涵蓋所有案例。

暫無
暫無

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

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