Java 9提供了一种创建Empty immutable List,set和Map的方法。
List list = List.of();
Set set = Set.of();
Map map = Map.of();
但是我无法理解创建空的不可变列表/集合/映射的实际用例是什么。
请帮助我理解一个空的不可变列表/ set / map的实际用例。
答案 0 :(得分:4)
想象一下应该对这些集合进行操作的常规数学运算。就像计算列表的交集一样。结果可能为空,在这种情况下,如果结果应不可变,则此方法会很有用。
public List<E> intersectLists(List<E> first, List<E> second) {
// If one is empty, return empty list
if (first.isEmpty() || second.isEmpty()) {
// Before Java 9: return Collections.emptyList();
return List.of();
}
// Compute intersection
...
}
当您通过getter公开内部数据结构但不希望调用者能够操作集合时,通常会使用不可变集合。
类似的变体是不可修改的集合。如果您直接引用位于包装器下方的可变集合,则可以对这些进行操作。通过这种方式,您可以强制用户使用您指定的方法进行操作。
public Graph {
private List<Node> nodes;
// Other stuff
...
public List<Node> getNodes() {
// Wrap container to make list unmodifiable
return Collections.unmodifiableList(nodes);
}
// User should use designated methods to manipulate instead
public void addNode(Node node) { ... }
public void removeNode(Node node) { ... }
}
答案 1 :(得分:3)
在Java 9之前,有Collections.emptyList()
,Collections.emptySet()
和Collections.emptyMap()
,它们明确且仅专门用于生成不可修改的空集合。 List.of()
等。也可以这样做是他们的API的内部一致性问题,而不是革命性的新功能。
但你的主要问题似乎是
请帮我理解一个空的不可变的实际用例 list / set / map。
这实际上是三个问题:
空集合的用例是什么?
空集合很有用,因为它们是真实数据和算法中出现的情况的自然表示。例如,“到目前为止哪些乘客已经办理登机手续?”什么都没有。哪些任务等待发送?我可以无休止地继续。
不可修改的集合有哪些用例?
可以传递对不可修改集合的引用,而不必担心集合将被修改(无论如何都要通过该引用)。请注意,假设不可修改性得到适当记录,所有参与者共享该对象可以依赖它而不是更改。除此之外,这对于安全地共享集合(和其他不可修改的对象)而不复制它们非常重要。
在这些用例中有哪些用例?
空集合在现实世界的数据和算法中自然发生,因此大多数不可修改集合的用例都包含空集合。
此外,您没有问过,但可能忽略了,虽然您无法将对象添加到不可修改的空集合中,但您可以将其替换为非空集合,或者在下次提供非空集合时,或者类似。
答案 2 :(得分:2)
每当一个类公开内部集合(通过公共属性,getter等)时,它必须复制整个集合或公开不可变集合,以避免调用者操纵内部数据结构。
例如,你可以有一些在内部使用但也通过getter公开的整数列表。由于列表不经常更新但经常读取,因此您决定使内部列表不可变(在每次更新时创建一个新列表)。这样你的getter就可以在不复制任何内容的情况下提交对内部列表的引用。现在,该列表迟早必须为空,需要一个空的不可变列表。
答案 3 :(得分:0)
当我们创建空的不可变列表/集合/映射时,是否有任何实际应用/用例
是的。这种情况很常见。
示例:我们正在编写一个方法,该方法返回在指定日期发布的与 COVID-19 相关的 Set
杂志文章。我们通过查询数据库、循环结果集中的行并构建 Article
对象列表来实现。
好吧,如果指定的日期在 2020 年之前,我们知道查询数据库并遵循该工作路径是没有意义的。而是只返回一个空的 Set
。并使其不可变,因为让调用代码无意中将值添加到我们知道语义上应该为空的集合中毫无意义。
public Set < Article > fetchCovid19ArticlesPublishedOnDate ( LocalDate datePublished )
{
if( datePublished.isBefore( LocalDate.of( 2020 , Month.JANUARY , 1 ) )
{ return Set.of() ; }
else
{
// Formulate SQL query
// Hit database.
// Process result set.
// Collect `Article` objects into set.
// Return set.
}
}