Java 控制流不只 if:進階控制結構(Advanced Control Structures)【Thinking in Java筆記(3-2)】

Java 控制流不只 if:進階控制結構(Advanced Control Structures)【Thinking in Java筆記(3-2)】
Photo by orbtal media / Unsplash

你是不是學會了 if、for、while 就覺得自己快要通靈 Java?慢著,還有一堆進階控制結構在等著你發現。像是 returnbreakcontinueswitch,這些指令就像交通號誌,會讓你的邏輯流程該停就停、該轉就轉,不然整個程式會像台沒方向盤的車,一路撞進除錯地獄

return 語句

這個語句就像是你在開會中間突然舉手說「我有急事先走」,然後還不忘把報告資料丟給老闆再閃人。用在方法裡,它表示你提前結束流程,有時還會回傳個東西交代一下

為什麼 return 很重要?

因為它可以幫你避免那種令人窒息的 if-else 俄羅斯套娃。你可以快速結束流程,而不是一路巢狀到底。來看個對比例子:

static int testVerbose(int a, int b) {
  int result;
  if (a > b) {
    result = 1;
  } else {
    if (a < b) {
      result = -1;
    } else {
      result = 0;
    }
  }
  return result;
}

你看這個 else 裡又包 else,就像過年去親戚家還要先被七個不同叔叔阿姨問什麼時候生小孩才能問到廁所在哪,累又囉嗦。來看看下面的簡潔版本:

public class IfElse2 {
  static int test(int testval, int target) {
    if(testval > target)
      return +1;
    else if(testval < target)
      return -1;
    return 0; // Match
  }
  public static void main(String[] args) {
    System.out.println(test(10, 5));
    System.out.println(test(5, 10));
    System.out.println(test(5, 5));
  }
} /* Output:
1
-1
0
*/

用生活例子理解

想像你在超市比價:

  • 如果A店貴,就立刻去B店(return +1)
  • 如果B店貴,就立刻去A店(return -1)
  • 價錢一樣?不買了(return 0)

return 的好處是可以在你知道答案時就直接閃人,不必拖泥帶水

void 方法也可以用 return 提早結束,不過不能 return 東西,頂多拍拍屁股走人

break 和 continue

這兩位是控制迴圈節奏的「情緒勒索大師」。

  • break:我受夠了這個迴圈,我現在就要中止它
  • continue:這輪我不玩了,跳過直接來下一回合

範例一:標準 for 迴圈中斷與略過

for(int i = 0; i < 100; i++) {
  if(i == 74) break; // 一看到 74 就立刻跳出整個迴圈
  if(i % 9 != 0) continue; // 不是 9 的倍數就跳過這次,不印出
  System.out.print(i + " ");
}
/* 0 9 18 27 36 45 54 63 72 */

這段邏輯會印出所有小於 74 的 9 的倍數。一旦遇到 i == 74 就直接中止

想像你在整理一疊刮刮樂,只對有中獎號碼(比如 9 的倍數)才感興趣,而且只處理到某個號碼(這裡是 74)。不想浪費時間多看一張沒中獎的或已過期的。這種情況下 breakcontinue 的組合,就像幫你自動跳過垃圾信件、並在某個點自動停止

範例二:使用 for-each 搭配自訂 range(需要搭配 range() 實作)

for(int i : range(100)) {
  if(i == 74) break;
  if(i % 9 != 0) continue;
  System.out.print(i + " ");
}
/* 0 9 18 27 36 45 54 63 72 */

這段和前面功能一樣,但使用了 for-each 語法,搭配一個自訂的 range(100) 方法,這種寫法對初學者來說可能比較陌生

簡單來說,range(100) 是書中作者自己寫的一個方法,它會回傳一組從 0 到 99 的整數集合,類似 Python 的 range()

這樣的寫法是為了讓迴圈更接近「我想要針對某個集合中的每個元素做點事」這種直觀想法。你不用自己去控制索引值遞增,只要關注「每個元素」就好

如果你還沒接觸過 Java 的集合或 Stream API,這種寫法可能會有點跳 tone,但在學習上,它是個很好的過渡,讓你開始接觸迴圈的「資料導向寫法」,而不是「索引導向寫法」

範例三:while(true) 無限迴圈的控制

int i = 0;
while(true) {
  i++;
  int j = i * 27;
  if(j == 1269) break; // 條件達成就跳出無限迴圈
  if(i % 10 != 0) continue; // 非 10 的倍數就略過
  System.out.print(i + " ");
}
/* 10 20 30 40 */

這是一種「我不確定要執行幾次,但目標一達成就馬上停止」的情境。想像你在等公車,但不知道幾號會先來(也不在乎),只要某台是你要搭的,就馬上跳上車走人。這種時候你不會說「我要等10台公車再決定」,你只要一台符合條件的就夠

while(true) 就像你一直站在站牌前看車來,break 則是當你看到想搭的車就上車離開。這在處理資料、等用戶輸入正確值、或不停檢查某個條件是否成立的時候都很實用,也讓程式碼不需要預設跑幾次,看起來更乾脆

switch 語句

你是不是也有這種人生選擇:今天要吃什麼?

  • case 火鍋:馬上開伙
  • case 披薩:打開外送 app
  • default:冰箱有什麼就吃什麼

switch 就是幫你這樣做決策的工具

switch (變數) {
    case 值1:
      // 做點什麼
      break;
    case 值2:
      // 做點別的
      break;
    default:
      // 都不符合時做這個
}
break 是結束 switch 的關鍵,否則程式會繼續執行下一個 case(這行為稱作 "fall-through")。這有時可用來讓多個 case 做同樣的事(像 case 'a': case 'e': 那樣),但初學者常常忘記加 break,導致程式做了預期之外的事

小提醒:

  • 從 Java 5 開始可以用 enum(列舉)類型
  • Java 7 開始支援 String,終於可以對話了

範例

public class VowelsAndConsonants {
  public static void main(String[] args) {
    Random rand = new Random(47);
    for(int i = 0; i < 100; i++) {
      int c = rand.nextInt(26) + 'a';
      System.out.print((char)c + ", " + c + ": ");
      switch(c) {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u': System.out.println("vowel");
                  break;
        case 'y':
        case 'w': System.out.println("Sometimes a vowel");
                  break;
        default:  System.out.println("consonant");
      }
    }
  }
} /* Output:
y, 121: Sometimes a vowel
n, 110: consonant
z, 122: consonant
b, 98: consonant
r, 114: consonant
n, 110: consonant
y, 121: Sometimes a vowel
g, 103: consonant
c, 99: consonant
f, 102: consonant
o, 111: vowel
w, 119: Sometimes a vowel
z, 122: consonant
...
*/

這個例子就像你遇到不同的人名:

  • 遇到 Alan、Eric、Ivan:都是母音(vowel)
  • 碰到 Yvonne 或 Walter:有時候他們也算母音(就像化學總是有例外)
  • 其他?通通當成子音算了(別計較)

結語:寫程式也要會「收、放、自如」

掌握 returnbreakcontinueswitch 這些控制結構,可以幫助你更清楚地表達程式的流程邏輯。簡化巢狀判斷、控制迴圈節奏,讓你的程式更簡潔、更容易維護