Collections.unmodifiableCollection 和 Collections.unmodifiableSet
Collections.unmodifiableCollection and Collections.unmodifiableSet
假设我有以下 Set
Set<String> fruits = new HashSet<String>();
fruits.add("Apple")
fruits.add("Grapes")
fruits.add("Orange")
如果我想创建一个防御副本,这样如果原始列表被修改,副本不会反映它,我可以这样做:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(new HashSet(fruits))
所以如果我这样做:
fruits.add("Pineapple")
println(unmodifiableFruits)
unmodifiableFruits
不会有菠萝。
或者我可以这样做:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)
结果是一样的,unmodifiableFruits
不会有菠萝。
问题:
- 假设我将
fruits
作为参数传递给 class,首选方法是 Collections.unmodifiableCollection()
吗?
原因是,我 read 在构造函数中声明 new
是一种不好的做法,如果我要使用 Collections.unmodifiableSet()
,我需要声明一个 new HashSet<String>(fruits)
.
为什么我不能这样做?
Collections.unmodifiableSet(fruits)
并让它 return 成为一个不可修改的集合。
相反,我必须这样做:
Collections.unmodifiableSet(new HashSet<String>(fruits))
是不是因为Set是一个接口,不知道要return哪个实现?
Groovy 具有增强的集合方法,这意味着它已将方法添加到标准集合 类.
其中一个方法是 toSet()
:
Convert a Collection to a Set. Always returns a new Set even if the Collection is already a Set.
Example usage:
def result = [1, 2, 2, 2, 3].toSet()
assert result instanceof Set
assert result == [1, 2, 3] as Set
当你这样写的时候:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)
它意味着一个 .toSet()
调用将 unmodifiableCollection
返回的 Collection
强制转换为 Set
, 隐式复制数据 .
当你这样写的时候:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(fruits)
返回值已经是一个Set
,所以不会调用toSet()
,意思是unmodifiableFruits
和fruits
共享数据
这就是为什么在使用 unmodifiableSet
时必须通过添加 new HashSet(...)
.
显式复制数据的原因
Is using Collections.unmodifiableCollection()
the proper way when passing a set into the constructor?
绝对不是。 使用 unmodifiableCollection()
并分配给 Set
,隐式调用 toSet
复制数据,隐藏了执行副本的事实。
为了确保代码的可读性,即任何阅读代码的人(包括 3 年后的你自己)都会理解代码的作用,使用复制构造函数编写代码以显式复制数据。
嗯,当然,除非这是一个代码混淆练习,在这种情况下,这是一个很好的误导技巧。
假设我有以下 Set
Set<String> fruits = new HashSet<String>();
fruits.add("Apple")
fruits.add("Grapes")
fruits.add("Orange")
如果我想创建一个防御副本,这样如果原始列表被修改,副本不会反映它,我可以这样做:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(new HashSet(fruits))
所以如果我这样做:
fruits.add("Pineapple")
println(unmodifiableFruits)
unmodifiableFruits
不会有菠萝。
或者我可以这样做:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)
结果是一样的,unmodifiableFruits
不会有菠萝。
问题:
- 假设我将
fruits
作为参数传递给 class,首选方法是Collections.unmodifiableCollection()
吗?
原因是,我 read 在构造函数中声明 new
是一种不好的做法,如果我要使用 Collections.unmodifiableSet()
,我需要声明一个 new HashSet<String>(fruits)
.
为什么我不能这样做?
Collections.unmodifiableSet(fruits)
并让它 return 成为一个不可修改的集合。
相反,我必须这样做:
Collections.unmodifiableSet(new HashSet<String>(fruits))
是不是因为Set是一个接口,不知道要return哪个实现?
Groovy 具有增强的集合方法,这意味着它已将方法添加到标准集合 类.
其中一个方法是 toSet()
:
Convert a Collection to a Set. Always returns a new Set even if the Collection is already a Set.
Example usage:
def result = [1, 2, 2, 2, 3].toSet() assert result instanceof Set assert result == [1, 2, 3] as Set
当你这样写的时候:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)
它意味着一个 .toSet()
调用将 unmodifiableCollection
返回的 Collection
强制转换为 Set
, 隐式复制数据 .
当你这样写的时候:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(fruits)
返回值已经是一个Set
,所以不会调用toSet()
,意思是unmodifiableFruits
和fruits
共享数据
这就是为什么在使用 unmodifiableSet
时必须通过添加 new HashSet(...)
.
Is using
Collections.unmodifiableCollection()
the proper way when passing a set into the constructor?
绝对不是。 使用 unmodifiableCollection()
并分配给 Set
,隐式调用 toSet
复制数据,隐藏了执行副本的事实。
为了确保代码的可读性,即任何阅读代码的人(包括 3 年后的你自己)都会理解代码的作用,使用复制构造函数编写代码以显式复制数据。
嗯,当然,除非这是一个代码混淆练习,在这种情况下,这是一个很好的误导技巧。