網頁

2019/7/29

Java 9 不可變的集合 Immutable Collections

Java 9 提供了如List.of()Map.of()Set.of()等靜態工廠方法來建立不可變的集合(Immutable Collections)。

在Java 9以前可使用Guava函式庫來建立Immutable Collections物件。

ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c"); 

Java 9的集合如ListSet,另外還有Map都新增了of()方法來建立Immutable Collections物件。

List<String> immutableList = List.of("a", "b", "c");
System.out.println(immutableList); // [a, b, c]
    
Set<String> immutableSet = Set.of("red", "yellow", "blue");
System.out.println(immutableSet);  // [blue, yellow, red]
    
Map<Integer, String> immuableMap = Map.of(1, "one", 2, "two", 3, "three");
System.out.println(immuableMap);   // {1=one, 3=three, 2=two}

Immutable Collections元素結構是不可被修改的,也就是一旦初始化後即不能新增刪除或修改集合中的元素,否則會丟出UnsupportedOperationException

而所謂"修改"Immutable Collections其實是指把修改後的元素放在另一個新建立的集合物件,此新的集合物件與原本"被修改"Immutable Collections物件擁有相同的結構。

Immutable Collections的不可變是指集合本身,並非指其所包含的元素。其包含的元素物件若非Immutable Object仍是可變的。

Map<Integer, String> mutableMap1 = new HashMap<>();
Map<Integer, String> mutableMap2 = new HashMap<>();
mutableMap1.put(1, "one");

List<Map<Integer, String>> immutableList = List.of(mutableMap1, mutableMap2);
immutableList.get(0).put(2, "two");

immutableList.forEach(System.out::println);
// {1=one, 2=two}
// {}

而Immutable與Unmodifiable並不相同,雖然兩者行為類似,也就是內容不可修改,不過Unmodifiable Collections中原本的集合仍是可變的,只不過包裝為不可修改;而Immutable Collections是根本上即不可變的。

例如下面試圖在unmodifiableList新增元素,則拋出UnsupportedOperationException錯誤。

List<String> mutableList = new ArrayList<>();
mutableList.add("a");
mutableList.add("b");
mutableList.add("c");

List<String> unmodifiableList = Collections.unmodifiableList(mutableList);
unmodifiableList.add("d"); // throw UnsupportedOperationException

但直接修改原本的可變集合mutableList仍可正常執行。

List<String> mutableList = new ArrayList<>();
mutableList.add("a");
mutableList.add("b");
mutableList.add("c");

List<String> unmodifiableList = Collections.unmodifiableList(mutableList);
// unmodifiableList.add("d"); // throw UnsupportedOperationException

mutableList.add("d");
unmodifiableList.forEach(System.out::print); // abcd


使用Immutable Collections的優點:

  • 安全性。因為不可變,所以可放心地傳送給第三方函式庫使用。
  • 執行緒安全(Thread-safe),Immutable Collections是執行緒安全的,不用擔資源競爭(Race condition)的問題。
  • 更好的效能,因為相較於可變的集合物件使用較少的記憶體空間

參考:

沒有留言:

張貼留言