Tips
做一個終身學習的人。
在本章中,主要介紹以下內容:
- 在JDK 9之前如何創建了不可變的list,set和map以及使用它們的問題。
- 如何使用JDK 9中的
List
接口的of()
靜態工廠方法創建不可變的list。
如何使用JDK 9中的Set
接口的of()
靜態工廠方法創建不可變的set。
如何使用JDK 9中的Map
接口的of()
,ofEntries()
和entry()
靜態工廠方法創建不可變的map。
一. 背景
Collection API由類和接口組成,提供了一種保存和操作不同類型的對象集合的方法,例如list,set和map。 它在Java SE 1.2版本中添加進來。 Java編程語言不支持Collection Literals,這是一種簡單易用的方式來聲明和初始化集合。 Collection Literals允許通過在緊湊形式的表達式中指定集合的元素來創建特定類型的集合。 Collection Literals的一個示例是一個列表文字,能夠創建一個列表,其中包含100和200的整數,如下所示:
List<Integer> list = [100, 200];
Collection Literals緊湊,使用簡單。 由於在創建時已知元素的數量,因此可以實現高效的內存使用。 它可以設計成不可變的,使其線程安全。
在Java編程語言中包含Collection Literals語法在JDK 9之前被考慮過幾次。 Java設計師決定不將Collection Literals添加到Java語言中,至少不在JDK 9中。在這一點上將Collection Literals添加到Java將需要太多的努力來獲得太少的收益。 他們決定通過在List
,Set
和Map
接口中添加靜態工廠方法來更新Collection API,從而可以輕松有效地創建小型的,不可變的集合來實現相同的目標。
現有的Collection API創建可變集合。 可以通過將可變集合包裝在另一個對象中創建一個不可變的(或不可修改的)集合,該對象只是原始可變對象的包裝器。 要在JDK 8或更早版本中創建兩個整數的無法修改的列表,通常使用以下代碼片段:
// Create an empty, mutable list
List<Integer> list = new ArrayList<>();
// Add two elements to the mutable list
list.add(100);
list.add(200);
// Create an immutable list by wrapping the mutable list
List<Integer> list2 = Collections.unmodifiableList(list);
這種做法有嚴重的缺陷。 不可變的list只是可修改list的包裝。 有意的是,將變量名為list
。 不能使用list2
變量修改列表。但是,仍然可以使用list
變量來修改列表,並且在使用list2
變量讀取list時將會反映出修改。 下面包含一個完整的程序來創建一個不可變的list,並顯示如何在以后更改其內容。
// PreJDK9UnmodifiableList.java
package com.jdojo.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PreJDK9UnmodifiableList {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
System.out.println("list = " + list);
// Create an unmodifiable list
List<Integer> list2 = Collections.unmodifiableList(list);
System.out.println("list2 = " + list2);
// Let us add an element using list
list.add(300);
// Print the contents of the list using both
// variables named list and list2
System.out.println("list = " + list);
System.out.println("list2 = " + list2);
}
}
輸出結果為:
list = [100, 200]
list2 = [100, 200]
list = [100, 200, 300]
list2 = [100, 200, 300]
輸出顯示,只要保留原始列表的引用,就可以更改其內容,並且不可變的list也不是真正不可變的! 解決此問題的方法是使用新的不可變list引用來覆蓋原始引用變量,如下所示:
List<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
// Create an unmodifiable list and store it in list
list = Collections.unmodifiableList(list);
注意,此示例使用多個語句來創建和填入不可變的list。 如果需要在類中聲明和初始化不可變的list作為實例或靜態變量,則該方法不起作用,因為它涉及多個語句。 這樣一個聲明需要簡單,緊湊,並且包含在一個聲明中。 如果在類中使用以前的代碼來實例變量,那么代碼將類似於以下代碼:
public class Test {
private List<Integer> list = new ArrayList<>();
{
list.add(100);
list.add(200);
list = Collections.unmodifiableList(list);
}
// ...
}
還有其他方式來聲明和初始化一個不可變的list,例如使用數組並將其轉換為list。 其中三種方式如下:
public class Test {
// Using an array and converting it to a list
private List<Integer> list2 = Collections.unmodifiableList( new ArrayList<>( Arrays.asList(100, 200)));
// Using an anonymous class
private List<Integer> list3 = Collections.unmodifiableList( new ArrayList<>(){{add(100); add(200);}});
// Using a stream
private List<Integer> list4 = Collections.unmodifiableList( Stream.of(100, 200).collect(Collectors.toList()));
// More code goes here
}
此示例證明可以在一個語句中具有不可變的list。 但是,語法是冗長的。 再是效率低下。 例如,只要在list中保存兩個整數,則需要創建具有后備數組對象的多個對象來保存這些值。
JDK 9通過向List
,Set
和Map
接口提供靜態工廠方法來解決這些問題。 該方法命名為of()
並且被重載。 在JDK 9中,可以聲明和初始化兩個元素的不可變列表,如下所示:
// Create an unmodifiable list of two integers
List<Integer> list = List.of(100, 200);
二. 不可變的list
JDK 9將of()
靜態工廠方法重載到List
接口。 它提供了一種簡單而緊湊的方式來創建不可變的list。 以下是of()
方法的所有版本:
static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)
of()
方法有11個特定版本來創建零到十個元素的list。 另一個版本采用可變參數來允許創建任何數量的元素的不可變的list。 你可能會想知道當使用可變參數的版本可以創建具有任意數量的元素的列表時,為什么有這么多版本的方法。 它們存在為性能原因。 API設計人員希望能夠有效地使用少量元素的列表。 使用數組實現可變參數。 存在具有非可變參數的方法,以避免將參數裝入數組中,這使得它們更有效率。 這些方法使用List
接口的特殊實現類用於較小的list。
of()
方法返回的list具有以下特征:
- 結構上是不可變的。 嘗試添加,替換或刪除元素會拋出
UnsupportedOperationException
異常。 - 不允許null元素。 如果列表中的元素為null,則拋出
NullPointerException
異常。 - 如果所有元素是可序列化的,那么它們也是可序列化的。
- 元素的順序與
of()
方法中指定的,與of(E… elements)
方法的可變參數版本中使用的數組相同。 - 對返回的列表的實現類沒有保證。 也就是說,不要指望返回的對象是
ArrayList
或任何其他實現List
接口的類。 這些方法的實現是內部的,不應該假定他們的類名。 例如,List.of()
和List.of("A")
可能會返回兩個不同類的對象。
Collections
類包含一個EMPTY_LIST
的靜態屬性,表示不可變的空list。 它還包含一個emptyList()
的靜態方法來獲取不可變的空list。singletonList(T object)
方法返回具有指定元素的不可變單例list。 以下代碼片段顯示了JDK 9和JDK 9之前創建不可變的空和單例list的方式。
// Creating an empty, immutable List before JDK 9
List<Integer> emptyList1 = Collections.EMPTY_LIST;
List<Integer> emptyList2 = Collections.emptyList();
// Creating an empty list in JDK 9
List<Integer> emptyList = List.of();
// Creating a singleton, immutable List before JDK 9
List<Integer> singletonList1 = Collections.singletonList(100);
// Creating a singleton, immutable List in JDK 9
List<Integer> singletonList = List.of(100);
如何使用of()
方法從數組中創建一個不可變的list? 答案取決於你想要從數組的列表。 可能需要一個list,其元素與數組的元素相同,或者可能希望使用數組本身作為列表中唯一元素的list。 使用List.of(array)
將調用of(E... elements)
方法,返回的列表將其元素與數組中的元素相同。 如您希望數組本身是list中的唯一元素,則需要使用List.<array-type>of(array)
方法,這將調用of(E e1)
方法,返回的列表將具有一個 元素,它是數組本身。 以下代碼使用Integer
數組來演示:
Integer[] nums = {100, 200};
// Create a list whose elements are the same as the elements
// in the array
List<Integer> list1 = List.of(nums);
System.out.println("list1 = " + list1);
System.out.println("list1.size() = " + list1.size());
// Create a list whose sole element is the array itself
List<Integer[]> list2 = List.<Integer[]>of(nums);
System.out.println("list2 = " + list2);
System.out.println("list2.size() = " + list2.size());
輸出結果為:
list1 = [100, 200]
list1.size() = 2
list2 = [[Ljava.lang.Integer;@27efef64]
list2.size() = 1
下面包含一個完整的程序,顯示如何使用List
接口的of()
靜態工廠方法來創建不可變的list。
// ListTest.java
package com.jdojo.collection;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// Create few unmodifiable lists
List<Integer> emptyList = List.of();
List<Integer> luckyNumber = List.of(19);
List<String> vowels = List.of("A", "E", "I", "O", "U");
System.out.println("emptyList = " + emptyList);
System.out.println("singletonList = " + luckyNumber);
System.out.println("vowels = " + vowels);
try {
// Try using a null element
List<Integer> list = List.of(1, 2, null, 3);
} catch(NullPointerException e) {
System.out.println("Nulls not allowed in List.of().");
}
try {
// Try adding an element
luckyNumber.add(8);
} catch(UnsupportedOperationException e) {
System.out.println("Cannot add an element.");
}
try {
// Try removing an element
luckyNumber.remove(0);
} catch(UnsupportedOperationException e) {
System.out.println("Cannot remove an element.");
}
}
}
輸出結果為:
emptyList = []
singletonList = [19]
vowels = [A, E, I, O, U]
Nulls not allowed in List.of().
Cannot add an element.
Cannot remove an element .
三. 不可變的set
JDK 9在Set
接口中添加了of()
靜態工廠方法的重載。 它提供了一種簡單而緊湊的方式來創建不可變的set。 以下是of()
方法的所有版本:
static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
static <E> Set<E> of(E e1, E e2, E e3)
static <E> Set<E> of(E e1, E e2, E e3, E e4)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> Set<E> of(E... elements)
of()
方法的所有版本為性能都做了調整。 可以使用前11個版本來創建一個不可變的零到十個元素的set。 of
方法的前11個版本與可變參數的版本一起存在的原因是為了避免將參數裝入數組中,最多可設置10個元素。 可變參數的版本可用於創建一個包含任意數量元素的不可變set。
of()
方法返回的set具有以下特征:
- 結構上是不可變的。 嘗試添加,替換或刪除元素會拋出
UnsupportedOperationException
異常。 - 不允許null元素。 如果set中的元素為null,則拋出
NullPointerException
異常。 - 如果所有元素是可序列化的,那么它們是可序列化的。
- 不允許重復元素。 指定重復的元素會引發一個
IllegalArgumentException
。 - 元素的迭代順序是未指定的。
- 對於返回的集合的實現類不能保證。 也就是說,不要指望返回的對象是
HashSet
或任何其他實現Set
接口的類。 這些方法的實現是內部的,不應該假定他們的類名。 例如,Set.of()
和Set.of(“A”)
可能返回兩個不同類的對象。
Collections
類包含一個EMPTY_SET
的靜態屬性,表示不可變的空set。 它還包含emptySet()
的靜態方法來獲取不可變的空set。 它的singleton(T object)
方法返回具有指定元素的不可變單例set。 以下代碼片段顯示了JDK 9和JDK 9之前創建不可變的空和單例set的方法:
// Creating an empty, immutable Set before JDK 9
Set<Integer> emptySet1 = Collections.EMPTY_SET;
Set<Integer> emptySet2 = Collections.emptySet();
// Creating an empty Set in JDK 9
Set<Integer> emptySet = Set.of();
// Creating a singleton, immutable Set before JDK 9
Set<Integer> singletonSet1 = Collections.singleton(100);
// Creating a singleton, immutable Set in JDK 9
Set<Integer> singletonSet = Set.of(100);
以下代碼顯示了如何從數組中創建一個不可變的set。 可以有一個set的元素與數組的元素相同,或者可以使用集合作為唯一元素的集合。 注意,當使用數組元素作為集合的元素時,該數組不能具有重復的元素。 否則,Set.of()
方法將拋出IllegalArgumentException
異常。
Integer[] nums = {100, 200};
// Create a set whose elements are the same as the
// elements of the array
Set<Integer> set1 = Set.of(nums);
System.out.println("set1 = " + set1);
System.out.println("set1.size() = " + set1.size());
// Create a set whose sole element is the array itself
Set<Integer[]> set2 = Set.<Integer[]>of(nums);
System.out.println("set2 = " + set2);
System.out.println("set2.size() = " + set2.size());
// Create an array with duplicate elements
Integer[] nums2 = {101, 201, 101};
// Try creating a set with the array as its sole element
Set<Integer[]> set3 = Set.<Integer[]>of(nums2);
System.out.println("set3 = " + set3);
System.out.println("set3.size() = " + set3.size());
try {
// Try creating a set whose elements are the elements of
// the array. It will throw an IllegalArgumentException.
Set<Integer> set4 = Set.of(nums2);
System.out.println("set4 = " + set4);
} catch(IllegalArgumentException e) {
System.out.println(e.getMessage());
}
輸出結果為:
set1 = [100, 200]
set1.size() = 2
set2 = [[Ljava.lang.Integer;@47c62251]
set2.size() = 1
set3 = [[Ljava.lang.Integer;@3e6fa38a]
set3.size() = 1
duplicate element: 101
下面包含一個完整的程序,顯示如何使用Set
接口的of()
靜態工廠方法來創建不可變的set。 注意程序中包含元音元素的set的輸出。 組合的元素可能不會以創建set時指定的相同順序輸出,因為set不保證其元素的順序。
// SetTest.java
package com.jdojo.collection;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
// Create few unmodifiable sets
Set<Integer> emptySet = Set.of();
Set<Integer> luckyNumber = Set.of(19);
Set<String> vowels = Set.of("A", "E", "I", "O", "U");
System.out.println("emptySet = " + emptySet);
System.out.println("singletonSet = " + luckyNumber);
System.out.println("vowels = " + vowels);
try {
// Try using a null element
Set<Integer> set = Set.of(1, 2, null, 3);
} catch(NullPointerException e) {
System.out.println("Nulls not allowed in Set.of().");
}
try {
// Try using duplicate elements
Set<Integer> set = Set.of(1, 2, 3, 2);
} catch(IllegalArgumentException e) {
System.out.println(e.getMessage());
}
try {
// Try adding an element
luckyNumber.add(8);
} catch(UnsupportedOperationException e) {
System.out.println("Cannot add an element.");
}
try {
// Try removing an element
luckyNumber.remove(0);
} catch(UnsupportedOperationException e) {
System.out.println("Cannot remove an element.");
}
}
}
以下是輸出結果:
emptySet = []
singletonSet = [19]
vowels = [E, O, A, U, I]
Nulls not allowed in Set.of().
duplicate element: 2
Cannot add an element.
Cannot remove an element.
四. 不可變的map
JDK 9將of()
靜態工廠方法重載添到Map接口中。 它提供了一種簡單而緊湊的方式來創建不可變的map。 方法的實現為性能做了調整。 以下是of()
方法的11個版本,可以創建一個不可變的零到十個鍵值條目的map:
static <K,V> Map<K,V> of()
static <K,V> Map<K,V> of(K k1, V v1)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9)
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)
注意在of()
方法中的參數的位置。 第一個和第二個參數分別是map中第一個鍵值對的鍵和值;第三個和第四個參數分別是map中第二個鍵值對的鍵和值。 注意,在Map中,沒有像在List
和Set
中可變參數的of()
方法。 這是因為Map
條目包含兩個值(鍵值和值),並且Java中的方法中只能有一個可變參數。 以下代碼片段顯示了如何使用of()
方法創建map:
// An empty, unmodifiable Map
Map<Integer, String> emptyMap = Map.of();
// A singleton, unmodifiable Map
Map<Integer, String> singletonMap = Map.of(1, "One");
// A unmodifiable Map with two entries
Map<Integer, String> luckyNumbers = Map.of(1, "One", 2, "Two");
要創建具有任意數量條目的不可修改的Map
,JDK 9在Map
接口中提供了一個ofEntries()
的靜態方法,它的簽名如下:
<K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
要使用ofEntries()
方法,需要在Map.Entry
實例中包含每個map鍵值對。 JDK 9在Map
接口中提供了一個方便的entry()
靜態方法來創建Map.Entry
的實例。 entry()
方法的簽名如下:
<K,V> Map.Entry<K,V> entry(K k, V v)
為了保持表達式的可讀性和緊湊性,需要為Map.entry
方法使用靜態導入,並使用如下所示的語句來創建一個具有任意數量條目的不可修改的map:
import java.util.Map;
import static java.util.Map.entry;
// ...
// Use the Map.ofEntries() and Map.entry() methods to
// create an unmodifiable Map
Map<Integer, String> numberToWord =
Map.ofEntries(entry(1, "One"),
entry(2, "Two"),
entry(3, "Three"));
Map
接口的of()
和ofEntries()
方法返回的map具有以下特征:
- 在結構上是不可變的。 嘗試添加,替換或刪除條目會拋出
UnsupportedOperationException
異常。 - 不允許在鍵或值中為null。 如果map中的鍵或值為null,則拋出
NullPointerException
異常。 - 如果所有鍵和值都是可序列化的,它們是可序列化的。
- 不允許重復的鍵。 指定重復的鍵會引發
IllegalArgumentException
異常。 - 映射的迭代順序是未指定的。
- 對於返回的
Map
的實現類不能保證。 也就是說,不要指望返回的對象是HashMap
或實現Map
接口的任何其他類。 這些方法的實現是內部的,不應該假定他們的類名。 例如,Map.of()
和Map.of(1, "One")
可能會返回兩個不同類的對象。
Collections
類包含EMPTY_MAP
的靜態字段,表示不可變的空map。 它還包含一個emptyMap()
的靜態方法來獲取不可變的空map。 singletonMap(K key, V value)
方法返回具有指定鍵和值的不可變的單例map。 以下代段顯示了JDK 9和JDK 9之前創建不可變空map和單例map的方式:
// Creating an empty, immutable Map before JDK 9
Map<Integer,String> emptyMap1 = Collections.EMPTY_MAP;
Map<Integer,String> emptyMap2 = Collections.emptyMap();
// Creating an empty Map in JDK 9
Map<Integer,String> emptyMap = Map.of();
// Creating a singleton, immutable Map before JDK 9
Map<Integer,String> singletonMap1 =
Collections.singletonMap(1, "One");
// Creating a singleton, immutable Map in JDK 9
Map<Integer,String> singletonMap = Map.of(1, "One");
下面包含一個完整的程序,顯示如何使用Map
接口的of()
,ofEntries()
和entry()
靜態方法來創建不可變的
map。 請注意map中指定日期的順序以及輸出中顯示的順序。 它們可能不匹配,因為map更像set,不能保證其條目的檢索順序。
// MapTest.java
package com.jdojo.collection;
import java.util.Map;
import static java.util.Map.entry;
public class MapTest {
public static void main(String[] args) {
// Create few unmodifiable maps
Map<Integer,String> emptyMap = Map.of();
Map<Integer,String> luckyNumber = Map.of(19, "Nineteen");
Map<Integer,String> numberToWord =
Map.of(1, "One", 2, "Two", 3, "Three");
Map<String,String> days = Map.ofEntries(
entry("Mon", "Monday"),
entry("Tue", "Tuesday"),
entry("Wed", "Wednesday"),
entry("Thu", "Thursday"),
entry("Fri", "Friday"),
entry("Sat", "Saturday"),
entry("Sun", "Sunday"));
System.out.println("emptyMap = " + emptyMap);
System.out.println("singletonMap = " + luckyNumber);
System.out.println("numberToWord = " + numberToWord);
System.out.println("days = " + days);
try {
// Try using a null value
Map<Integer,String> map = Map.of(1, null);
} catch(NullPointerException e) {
System.out.println("Nulls not allowed in Map.of().");
}
try {
// Try using duplicate keys
Map<Integer,String> map = Map.of(1, "One", 1, "On");
} catch(IllegalArgumentException e) {
System.out.println(e.getMessage());
}
try {
// Try adding an entry
luckyNumber.put(8, "Eight");
} catch(UnsupportedOperationException e) {
System.out.println("Cannot add an entry.");
}
try {
// Try removing an entry
luckyNumber.remove(0);
} catch(UnsupportedOperationException e) {
System.out.println("Cannot remove an entry.");
}
}
}
輸出結果為:
emptyMap = {}
singletonMap = {19=Nineteen}
numberToWord = {1=One, 3=Three, 2=Two}
days = {Sat=Saturday, Tue=Tuesday, Thu=Thursday, Sun=Sunday, Wed=Wednesday, Fri=Friday, Mon=Monday}
Nulls not allowed in Map.of().
duplicate key: 1
Cannot add an entry.
Cannot remove an entry.
五. 總結
在Java語言中支持collection literals是非常需要的功能。 JDK 9替代了對collection literals的支持,更新了Collection API,而是在List
,Set
和Map
接口中添加了of()
靜態工廠方法,分別返回一個不可變的List
,Set
和Map
。該方法被重載,指定集合的零到十個元素。 List
和Set
接口提供了可變參數的of()
方法,用於創建一個包含任意數量的元素的List
和Set
。 Map
接口提供了ofEntries()
靜態工廠方法,用於創建一個不可變的任意數量條目的Map
。 Map
接口還包含一個靜態的entry()
方法,它接受一個鍵和一個值作為參數並返回一個Map.Entry
實例。 ofEntries()
和entry()
方法一起使用來創建任意數量條目的不可變的Map
。
這些接口中的新的靜態工廠方法為性能做了調整。 List.of()
和Set.of()
方法不允許使用null元素。 Set.of()
方法不允許重復的元素。 Map.of()
和Map.ofEntries()
方法不允許重復鍵,或者將null作為鍵或值。