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 = = > c l a s s j a v a . u t i l . I m m u t a b l e C o l l e c t i o n s 39 ==> class java.util.ImmutableCollections 39==>classjava.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 = = > c l a s s j a v a . u t i l . I m m u t a b l e C o l l e c t i o n s 49 ==> class java.util.ImmutableCollections 49==>classjava.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的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值