Java 初學者常見疑問:三元運算子、字串串接與型別轉換一次搞懂【Thinking in Java筆記(2-4)】

Java 初學者常見疑問:三元運算子、字串串接與型別轉換一次搞懂【Thinking in Java筆記(2-4)】
Photo by Safar Safarov / Unsplash

剛開始學Java,看到 ? :+=(int) 這些奇怪符號就頭痛嗎? 這篇文章不是什麼艱澀的理論筆記,而是從「你到底為什麼會用到這些東西」的角度出發,讓你在實際寫程式時不再卡關

什麼是三元運算子(Ternary If-Else Operator)?我為什麼不用 if-else?

三元運算子是一種更短的寫法,用來根據條件決定要回傳哪個值

語法:

boolean 條件 ? 條件為 true 時的值 : 條件為 false 時的值

假設你想根據一個數字 i 的值來計算不同結果:

return (i < 10) ? i * 100 : i * 10;

這句話意思是:「如果 i 小於 10,回傳 i * 100,否則回傳 i * 10。」

你可以跟下面這段 if-else 比較:

int result;
if (i < 10) {
  result = i * 100;
} else {
  result = i * 10;
}

功能一樣,但三元運算子更簡潔

範例程式碼:

public class TernaryIfElse {
  static int calculateUsingTernary(int i) {
    return i < 10 ? i * 100 : i * 10;
  }
  static int calculateUsingIfElse(int i) {
    if(i < 10)
      return i * 100;
    else
      return i * 10;
  }
  public static void main(String[] args) {
    print(calculateUsingTernary(9));  // 使用三元操作符計算,輸出: 900
    print(calculateUsingTernary(10)); // 使用三元操作符計算,輸出: 100
    print(calculateUsingIfElse(9));   // 使用標準if-else計算,輸出: 900
    print(calculateUsingIfElse(10));  // 使用標準if-else計算,輸出: 100
  }
} /* Output:
900
100
900
100
*/
提醒:
三元運算子適合用在「值的選擇」,像是簡單的 if-else
如果條件很複雜、有副作用、或需要做多件事,還是乖乖寫完整的 if-else 比較好,別把自己繞進地獄

為什麼字串加法(+)那麼奇怪?

在 Java 裡用 + 號加字串很直覺,但也容易踩雷

你可能看過這種程式:

System.out.println("結果:" + 1 + 2);

你以為會輸出 結果:3?錯!結果其實是:

結果:12

為什麼這樣?

Java 是從左到右執行的,而且只要有一邊是字串,後面的都會被轉成字串再做「字串串接」。所以:

  • "結果:" + 1 → "結果:1"
  • "結果:1" + 2 → "結果:12"

要改正這種情況,你應該這樣寫:

System.out.println("結果:" + (1 + 2)); // 輸出:結果:3

更完整範例:

public class StringOperators {
  public static void main(String[] args) {
    int x = 0, y = 1, z = 2;
    String s = "x, y, z ";
    System.out.println(s + x + y + z);
    System.out.println(x + " " + s); // Converts x to a String
    s += "(summed) = "; // Concatenation operator
    System.out.println(s + (x + y + z));
    System.out.println("" + x); // Shorthand for Integer.toString()
  }
} /* Output:
x, y, z 012
0 x, y, z
x, y, z (summed) = 3
0
*/

關鍵觀念:

  • 遇到 + 號,如果左邊是字串,Java 會自動把右邊轉成字串再做「拼接」
  • 不管你是整數、布林值或浮點數,通通會變成字串

小技巧:

  • 使用括號讓加法優先執行:"合計:" + (a + b)
  • 想強制轉成字串可以用:String.valueOf(a)"" + a
  • 想清楚「誰先變字串」可以幫助你少寫很多 bug

預防踩雷:

不要以為你在做加法,Java 有可能只是在幫你拼字串。尤其是 Debug 訊息那種 log 很多值的情況,一不小心就會拼錯

三、型別轉換運算子(Casting Operators)是什麼?為什麼有些需要強制轉型?

在程式中,有時需要將一種資料型別轉換為另一種。Java 通常會在安全的情況下自動幫你轉換,但當資料可能遺失或精度改變時,你就必須手動指定轉型方式,這就是「強制轉型」

範例:

public class Casting {
  public static void main(String[] args) {
    int i = 200;
    long lng = (long)i;    // 無需顯式轉換,因為 int 到 long 是 Widening
    lng = i;               // "Widening," so cast not really required
    long lng2 = (long)200; // 直接將字面量轉為 long
    lng2 = 200;            // 擴展轉換,自動處理
    // A "narrowing conversion":
    i = (int)lng2; // Cast required,因為 long 到 int 可能導致資料丟失
  }
} 

窄化轉換與擴展轉換

  • 窄化轉換(Narrowing Conversion):
    • 大型別 → 小型別,例如 long → int
    • 可能導致資料遺失,需要顯式轉型
  • 擴展轉換(Widening Conversion):
    • 小型別 → 大型別,例如 int → long
    • 這是安全的,Java 會自動處理

2. 截斷與進位(Truncation and Rounding)

從浮點數轉換為整數時,小數會被直接「砍掉」,而非四捨五入

截斷範例:

public class CastingNumbers {
  public static void main(String[] args) {
	double above = 0.7, below = 0.4;
	float fabove = 0.7f, fbelow = 0.4f;
	print("(int)above: " + (int)above);
	print("(int)below: " + (int)below);
	print("(int)fabove: " + (int)fabove);
	print("(int)fbelow: " + (int)fbelow);
  }
} /* Output:
(int)above: 0
(int)below: 0
(int)fabove: 0
(int)fbelow: 0
*/
所有結果都是 0,因為它直接砍掉小數點之後的部分

如果你真的想要四捨五入?

使用 Math.round() 方法

public class RoundingNumbers {
  public static void main(String[] args) {
	double above = 0.7, below = 0.4;
	float fabove = 0.7f, fbelow = 0.4f;
	print("Math.round(above): " + Math.round(above));
	print("Math.round(below): " + Math.round(below));
	print("Math.round(fabove): " + Math.round(fabove));
	print("Math.round(fbelow): " + Math.round(fbelow));
  }
} /* Output:
Math.round(above): 1
Math.round(below): 0
Math.round(fabove): 1
Math.round(fbelow): 0
*/

3. 型別提升(Promotion)

當你在表達式中混用不同型別(如 int 與 long),Java 會自動將較小的型別轉為較大的型別來確保運算正確:

  • int + long → long
  • float + double → double
如果你想把這些運算結果放進比較小的型別變數裡,還是得自己強制轉型,否則編譯器會報錯

Java 為什麼沒有 sizeof?我怎麼知道型別大小?

在 C/C++ 中,sizeof() 函數用於獲取資料型別或物件所佔用的記憶體大小,這在不同位元系統間的程式碼移植中非常重要

然而,Java 並未提供類似的 sizeof 運算子,原因如下:

  • 固定的資料型別大小: Java 的基本資料型別在所有平台上都有固定的大小。例如,int 永遠是 32 位元,long 永遠是 64 位元。
  • 跨平台性: Java 是跨平台語言,不讓你碰底層
  • 記憶體管理: Java 有自動垃圾回收機制,JVM 幫你管記憶體,自己不用算

所以 Java 沒有 sizeof() 是刻意設計,讓你更少煩惱平台差異


總結:看完你應該學會了...

主題學到什麼實際應用
三元運算子快速選擇值a > b ? a : b 這種判斷式
字串串接+ 處理方式不直觀記得用括號包數學運算
型別轉換強制轉型與精度處理理解何時該手動轉換與資料截斷風險
Java 沒 sizeofJVM 幫你處理底層不用煩記憶體管理

學 Java 的路很長,別讓這些基礎卡住你。如果這篇有幫助你理解一點點,記得把它存在書籤裡,或分享給也在學 Java 的朋友(他們也需要被拯救)