DEV Community

codemee
codemee

Posted on

Java 複合運算的陷阱

Java 的複合運算是大家常用的運算, 不過有一個細節可能一般的教學文章不會提到, 這可能會讓你遇到莫名其妙的錯誤。

複合運算並不等於一般運算加設定運算

有些教學文章會說複合運算就等於拆解開來的一般運算加上設定運算, 例如 a+=b 就等同於 a = a + b, 不過這是有問題的, 請看以下範例:

jshell> short s = 2
s ==> 2

jshell> s = s + 2
|  Error:
|  incompatible types: possible lossy conversion from int to short
|  s = s + 2
|      ^---^

jshell>

jshell> s += 2
$36 ==> 4
Enter fullscreen mode Exit fullscreen mode

你可以看到應該是同樣的運算以複合運算沒問題, 但是不用複合運算卻出錯?從錯誤訊息可以看出來, 因為 2 是 int, 所以進行加法運算時, 會把 short 型別的 s 放寬轉型成 int, 但是當要把計算結果放回 s 時, 就會發生無法自動從 int 縮窄轉成 short 的錯誤。

但是複合運算卻不會發生這樣的問題, 這很明顯告訴我們兩種運算並不完全相同。

複合運算隱含了強制轉型

如果你查看 Java 語言的規格書, 就會發現複合運算的說明如下:

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

也就是說, 複合運算在設定之前, 會強制將運算結果轉型回變數的型別, 因此前面複合運算的版本其實等同以下程式碼:

jshell> s = (short)(s + 2)
Enter fullscreen mode Exit fullscreen mode

由於加上了強制運算, 所以原本 int 型別的計算結果就會被強制轉回範圍較窄的 short 型別, 不會發生錯誤了。

當然, 因為這樣的機制, 也要注意複合運算可能會溢位, 例如:

jshell> s *= 10000
$39 ==> -5536

jshell> s
s ==> -5536
Enter fullscreen mode Exit fullscreen mode

小結

學習程式語言時, 很容易因為程式可以得到正確結果而忽略了其中的細節, 本文僅是其中的一個小例子, 提醒大家要多留意, 否則遇到錯誤時往往無法找出真正的原因。

Top comments (0)