Java集合正在發展

Java 9:集合的便利工廠方法
Java 9引入了創建不可變集合的新方法。在某個時候,我們都編寫了看起來像這樣的代碼:
List moods = Arrays.asList(“HAPPY”, “SAD”);

從Java 9開始,您現在可以編寫以下代碼:
List moods = List.of(“HAPPY”, “SAD”);

雖然節省六個字符對於那些喜歡非常簡潔的代碼的人來說可能會令人興奮,但是這似乎並不是一個巨大的改進。
但是,重要的是要意識到,第二種情況創建了一個不可變的列表。我們可能已經陷入思考Arrays.asList返回不可變列表的陷阱,因爲不可能追加到它:
jshell> List moods = Arrays.asList(“HAPPY”, “SAD”);
moods ==> [HAPPY, SAD]
jshell> moods.add(“ANGRY”)
| java.lang.UnsupportedOperationException thrown
| at AbstractList.add (AbstractList.java:153)
| at AbstractList.add (AbstractList.java:111)
| at (#2:1)

但是,可以在列表的限制內進行更改:
jshell> moods.set(0, “ANGRY”)
$3 ==> “HAPPY”
jshell> System.out.println(moods)
[ANGRY, SAD]

在編寫此代碼時,這可能不是故意的。相反,我們真正想要的是:
List moods = Collections.unmodifiableList(Arrays asList(“HAPPY”, “SAD”));

現在您可以看到:
List moods = List.of(“HAPPY”, “SAD”);

…確實會返回一個不可變的列表,它不僅比Java-9之前的版本短很多,而且比簡單地使用Arrays.asList更正確。
這對列表很有用,但更有用的是爲“集”和“地圖”添加了類似的方法。要在Java 9之前創建一個不可變的Set,可以使用以下方法:
Set moods = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(“HAPPY”, “SAD”)));

即使使用靜態導入來減少一些噪音,這也確實令人不快。在Java 9中,它很簡單:
Set moods = Set.of(“HAPPY”, “SAD”);

還有一些用於創建地圖的工廠方法。在Java 9之前,如果我們想創建一個具有一組固定值的Map,則必須做一些漫長的事情:
Map<String, Mood> wordToMood = new HashMap<>();
wordToMood.put(“happy”, HAPPY);
wordToMood.put(“good”, HAPPY);
wordToMood.put(“great”, HAPPY);
//… more values
wordToMood.put(“horrible”, SAD);
wordToMood.put(“bad”, SAD);
wordToMood.put(“awful”, SAD);

如果我們想將其初始化爲常量(例如靜態字段),則情況更糟,因爲必須將其放置在靜態塊中的某個位置,並將其包裝在unmodifiableMap中只會增加噪音。在Java 9中,可以是:
Map<String, Mood> wordToMood
= Map.ofEntries(Map.entry(“happy”, HAPPY),
Map.entry(“good”, HAPPY),
Map.entry(“great”, HAPPY)
//…more values
Map.entry(“horrible”, SAD),
Map.entry(“bad”, SAD),
Map.entry(“awful”, SAD));

靜態導入也可以使其更加簡潔。該Map.ofEntries方法適用於任意數量的鍵/值對,因爲每對都包裝在Map.entry中,並且ofEntries方法採用一個變量。如果Map的值少於十個,我們可能要使用便捷的Map.of方法,該方法最多包含十個鍵/值參數:
Map<String, Mood> wordToMood = Map.of(“happy”, HAPPY,
“good”, HAPPY,
“great”, HAPPY,
“horrible”, SAD,
“bad”, SAD,
“awful”, SAD);

Java 10:創建集合的不變副本
Java 9引入了這些工廠方法,以使從已知值創建新的不可變集合變得更加容易。Java 10認識到這不是我們創建集合的唯一方法,因此引入了更多從現有集合或操作中創建不可變集合的方法。
現在有一種簡單的方法可以創建不可變的Collection,它是現有Collection的副本。在Java 10之前,您可以使用副本構造函數創建一個新列表,該列表是現有集合的副本:
List newCopyOfCollection = new ArrayList<>(moods);

在這種情況下,即使原始集合的心情是不可變的/不可修改的,新集合也不是:
jshell> List newCopyOfCollection = new ArrayList<>(moods);
newCopyOfCollection ==> [HAPPY, SAD]
jshell> newCopyOfCollection.add(“ANGRY”)
$5 ==> true
jshell> System.out.println(newCopyOfCollection)
[HAPPY, SAD, ANGRY]

要創建無法更改的列表,必須將其包裝在不可修改的列表中:
jshell> List newCopyOfCollection = Collections.unmodifiableList(new ArrayList<>(moods));
newCopyOfCollection ==> [HAPPY, SAD]
jshell> newCopyOfCollection.add(“ANGRY”)
| java.lang.UnsupportedOperationException thrown
| at Collections$UnmodifiableCollection.add
(Collections.java:1056)
| at (#8:1)

特別是對於列表,您也可以使用Collections.copy,但是語法有點笨拙,如果目標列表設置不正確,很容易出現運行時錯誤。
在Java 10中,從現有Collection創建一個新的不可變列表要容易得多:
List newCopyOfCollection = List.copyOf(moods);

如您所料,您無法添加或刪除元素或更改列表中的項目:
jshell> List newCopyOfCollection = List.copyOf(moods);
newCopyOfCollection ==> [HAPPY, SAD]
jshell> newCopyOfCollection.add(“ANGRY”)
| java.lang.UnsupportedOperationException thrown
| at ImmutableCollections.uoe
(ImmutableCollections.java:71)
| at
ImmutableCollections$AbstractImmutableList.add
(ImmutableCollections.java:77)
| at (#21:1)

Set還存在類似的方法:
Set setCopyOfCollection = Set.copyOf(moods);

…和地圖。Map版本需要複製另一個Map,而不是Collection:
Map<String, Mood> copyOfMoodMap = Map.copyOf(wordToMood);

Java 10:從流創建不可變集合
Java 10通過在Collector上添加toUnmodifiableList,toUnmodifiableSet和toUnmodifiableMap方法,很容易從Stream操作創建不可變的集合。這意味着從Java 10中,不僅可以從某些已知值或通過複製現有Collection或Map來創建不可變的Collection,還可以從Stream操作中創建不可變的Collection。
例如,假設我們有一個Stream操作,該操作接受一個句子並將其轉換爲唯一單詞的列表:
List uniqueWords =
Pattern.compile("\s*[^\p{IsAlphabetic}]+\s*").splitAsStream(message)
.map(String::toLowerCase)
.distinct()
.collect(Collectors.toList());

此列表是包含結果的簡單ArrayList,可以更改:
jshell> String message = “I am so so happy today, and I am not happy every day”;
message ==> “I am so so happy today, and I am not happy every day”
jshell> List uniqueWords = Pattern.compile("\s*[^\p{IsAlphabetic}]+\s*").splitAsStream(message).
…>
map(String::toLowerCase).
…> distinct().
…>
collect(Collectors.toList());
uniqueWords ==> [i, am, so, happy, today, and, not, every, day]
jshell> uniqueWords.getClass()
$35 ==> class java.util.ArrayList
jshell> uniqueWords.add(“SAD”)
$36 ==> true
jshell> System.out.println(uniqueWords)
[i, am, so, happy, today, and, not, every, day, SAD]

如果此流操作的目標是返回一些固定的結果,則我們可能不希望返回ArrayList,而是返回某種不可變的列表。在Java 10中,我們可以這樣做:
List uniqueWords
= Patternc ompile("\s*[^\p{IsAlphabetic}]+\s*"
.splitAsStream(message)
.map(String::toLowerCase)
.distinct()
.collect(Collectors.toUnmodifiableList());

這將返回一個無法更改的列表:
jshell> List uniqueWords = Pattern.compile("\s*[^\p{IsAlphabetic}]+\s*").splitAsStream(message).
…>
map(String::toLowerCase).
…>
distinct().
…>
collect(Collectors.toUnmodifiableList());
uniqueWords ==> [i, am, so, happy, today, and, not, every, day]
jshell> uniqueWords.getClass()
39==>classjava.util.ImmutableCollections39 ==> class java.util.ImmutableCollectionsListN
jshell> uniqueWords.add(“SAD”)
| java.lang.UnsupportedOperationException thrown
| at ImmutableCollections.uoe
(ImmutableCollections.java:71)
| at
ImmutableCollections$AbstractImmutableList.add
(ImmutableCollections.java:77)
| at (#40:1)

還有Collectors.toUnmodifiableSet,在這種情況下可能更合適,因爲Collection僅包含唯一值。
Collectors.toUnmodifiableMap用於創建不可變的Map,與toMap一樣,它有點棘手,因爲這意味着我們需要提供函數來定義鍵和值。如果我們更改示例以使用Map計算句子中每個單詞的次數,我們可以演示如何收集到不可變的Map中:
Map<String, Long> wordCount = Pattern.compile("\s*[^\p{IsAlphabetic}]+\s*").
splitAsStream(message).
map(String::toLowerCase).
collect(Collectors.toUnmodifiableMap(Function.identity(), word -> 1L, (oldCount, newVal) -> oldCount + newVal));

和以前一樣,我們可以看到無法將值添加到此Map中或從中刪除:
jshell> Map<String, Long> wordCount = Pattern.compile("\s*[^\p{IsAlphabetic}]+\s*").
splitAsStream(message).
…>
map(String::toLowerCase).
…>
collect(Collectors.toUnmodifiableMap(Function.identity(),
…>
word -> 1L,
…>
(oldCount, newVal) -> oldCount + newVal));
wordCount ==> {and=1, i=2, am=2, day=1, so=2, every=1, today=1, not=1, happy=2}
jshell> wordCount.getClass()
49==>classjava.util.ImmutableCollections49 ==> class java.util.ImmutableCollectionsMapN
jshell> wordCount.put(“WORD”, 1000L)
| java.lang.UnsupportedOperationException thrown
| at ImmutableCollections.uoe
(ImmutableCollections.java:71)
| at
ImmutableCollections$AbstractImmutableMap.put
(ImmutableCollections.java:558)
| at (#50:1)

總之,我們可以看到Java正在不斷髮展,以使我們的開發人員更容易編寫方便且正確的代碼。其中一些更改只是對現有API的少量補充,因此很容易在較大的語言更改中錯過它們。集合在Java的最新版本中得到了發展,如果我們保持最新狀態並使用這些更改,我們會發現自己的生活要容易一些。
最後,開發這麼多年我也總結了一套學習Java的資料與面試題,如果你在技術上面想提升自己的話,可以關注我,私信發送領取資料或者在評論區留下自己的聯繫方式,有時間記得幫我點下轉發讓跟多的人看到哦。在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章