繼讀來說說 Scala 為什麼吸引我唄,在這一篇裡面與其他語言比較的部份沒那麼多,大部份是在講 Scala 和 Java 的一些不同,以及一些可以讓你比較省事的功能。
偏好 Immutable 物件,但也給你選擇的自由
由於 Scala 將 Functional Programming (FP) 做為預設偏好的編程典範,所以也提倡所謂的 immutable 物件,至於什麼是 immutable 物件呢?簡單地來說,就是不論你對他做什麼樣的操作,他都永遠不會改變。
其中一個註明的例子是 Java 當中的 String 物件,不論你呼叫 String 裡的哪一個函式,原來的 String 物件是不會被更動的,只是產生了一份新的 String 物件而已。
例如:
public class Test { public static void main (String [] args) { String str1 = "Hello World"; String str2 = str1.substring(0, 5); System.out.println (str1); // "Hello World" System.out.println (str2); // "World" } }
同樣的,在 Scala 當中,幾乎大部份預設的資料結構都是 immutable 的,特別明顯的就是 Collection 的相關類別,像是 List、Map 這些東西,如果沒有特別指明的話,所使用的都是 immutable 的版本。
例如:
val xs1 = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val xs2 = xs1.filter(_ % 2 == 0) println (xs1) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) println (xs2) // List(2, 4, 6, 8, 10)
至於 immutable 物件的好處,諸如 Thread-safe 等等,其他地方都已經把他講到爛了,所以這邊就不再贅述。
不過要特別提的一點,就是 Scala 給你選擇的自由,他把一整套工具都給你了,所以當你發現真的需要 mutable 物件的 Collection 時候,也沒有問題,只要選用 scala.collection.mutable 裡的東西就可以了,幾乎所有的容器都有一份 immutable 和 mutable 版本,所以你可以選擇適合自己需求的東西。
在 Scala 中的 == 運算子
Java 當中的 == 運算子在不同的狀況下有不同的語意:
- 當比較的變數是基本資料型態(如 int 或 boolean 這些),比的是『值』
- 當比較的變數是 Reference,比的是該 Reference 是不是指到同一個物件
一個常常用來示範 Java 中 == 運算子的範例程式如下:
public class Test { public static void main (String [] args) { int x1 = 123; int x2 = 100 + 20 + 3; String strPool1 = "Hello World"; String strPool2 = "Hello World"; String str1 = new String("Hello World"); String str2 = new String("Hello World"); // true,因為值相等,都是 123 System.out.println (x1 == x2); // true,因為指到 String Pool 裡的同一個物件 System.out.println (strPool1 == strPool2); // false,雖然值都是 "Hello World",但是是不同物件 System.out.println (str1 == str2); } }
相較之下,由於 Scala 是個純物件導向語言,已經沒有基本資料型態和 Reference 資料型態的概念,所以對於 == 的處理也有一點不同--在 Scala 當中,== 用以比較值(在物件有正確實作 hashCode 與 equals 時)。
簡單的來說,在 Scala 當中的 x == y 約相當於在 Java 中呼叫 x.equals(y) 這樣子,這是和 Java 差別滿多的一點。也因為如此,如果真的需要比較兩個變數是不是指到同一份物件,Scala 另外提供了一個叫做 eq 的運算子。
範例如下:
val x1 = 123 val x2 = 100 + 20 + 3 val strPool1 = "Hello World" val strPool2 = "Hello World" val str1 = new String("Hello World") val str2 = new String("Hello World") val xs1 = List(1, 2, 3) val xs2 = List(1, 2) + List(3) println (x1 == x2) // true println (strPool1 == strPool2) // true, 內容都是 "Hello World" println (strPool1 eq strPool2) // true, 同一個物件 println (str1 == str2) // true, 內容都是 "Hello World" println (str1 eq str2) // false, 不同的物件 println (xs1 == xs2) // true, 內容都是 List(1, 2, 3) println (xs1 eq xs2) // false, 不同的物件
但相較之下,如果你沒有自己實作 equals 這個 method 的話,預設會去比較兩個變數是不是指到相同的物件,算是比較要注意的地方。
class MyData(x: Int) val data1 = new MyData(3) val data2 = new MyData(4) println (data1 == data2) // false,因為沒有實作 equals println (data1 eq data2) // false,因為是不同的物件
回響