天天看點

Mutable and Immutable Collections的差別

在寫scala的時候,常常不太明白Mutable and Immutable Collections的用法和差別。官方文檔說得很清楚:

A mutablecollection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change. 

但是我們在用的時候很發現這兩個并沒什麼異樣。

一、擺例子,抛出疑惑

例子1-1:

object Test1 extends App() {
  var map = new scala.collection.mutable.HashMap[Int, String];
  map += (1 -> "1");
  map += (2 -> "2");
  map += (3 -> "3")
  map += (4 -> "4");
  map += (1 -> "5");
  println(map.mkString("\n"));
}
           

結果:

1 -> 5
2 -> 2
3 -> 3
4 -> 4
           

這裡可以看出是沒什麼問題的,但是如果把第一行改為immutable的HashMap,你會發現結果依舊沒有變。(可能順序有點變化)

例子1-2:

var map = new scala.collection.immutable.HashMap[Int, String];
           

結果:

1 -> 5
2 -> 2
3 -> 3
4 -> 4
           

那麼就奇怪了,其實對于這個基礎好的碼農一眼就知道了原因,所有的的存在某種問題或陰謀都在+=這個操作符上,每次+=操作之後都會傳回一個新的對象

也就是說這裡共産生了6個map新對象。是以最後輸出map的時候其實是最新的那個對象,原來的對象并沒有變化。

那麼問題是否這樣呢?

二、深入驗證假設。

例子2-1:

object Test1 extends App() {
  var map = new scala.collection.mutable.HashMap[Int, String];
  map += (1 -> "1");
  map += (2 -> "2");
  var tem = map;
  tem += (1 -> "5");
  
  println(map.mkString(" || "));
  println("---------------")
  println(tem.mkString(" || "));
}
           

結果:

2 -> 2 || 1 -> 5

---------------

2 -> 2 || 1 -> 5

奇怪的現象又來了,不是說好的+=操作每次都會傳回新對象嗎?這個試驗的結果很明顯最後的tem對象 += 的改變仍然會引起map對象的改變。

也就是說 

tem += (1 -> "5");
           

根本不會引起一個新對象的産生。它們都指向同一個記憶體空間。fuck,我要砸鍵盤了!!!!

Mutable and Immutable Collections的差別

   别急,請看第二個例子

例子2-2:

修改第一行為:

var map = new scala.collection.immutable.HashMap[Int, String];
           

結果:

1 -> 1 || 2 -> 2

---------------

1 -> 5 || 2 -> 2

好了,這個倒是符合我們當初的假設,暫時不砸鍵盤。

三、總結:

相信聰明的人一下子就能看出差別了。scala用心良苦,在+=這個操作符上為我們花了不少功夫。

+=這個操作符,如果操作的對象是可變的,它會自動調用對象的update方法(具體對象看具體操作),相當于更新或者追加的操作。

如果對象是不可變的,它就會傳回一個新的對象。

問題擴充:為什麼要花費精力弄明白可變與不可變對象的差別?(這個涉及到多線程安全,循環周遊等,具體自己上網查)