假设我有以下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
作为类的参数传递,则首选方法Collections.unmodifiableCollection()
是吗? 原因是,我read在构造函数中声明new
是一种不好的做法,如果我要使用Collections.unmodifiableSet()
,则需要声明一个{{1 }}。
我为什么不能这样做?
new HashSet<String>(fruits)
并使其返回不可修改的集合。
相反,我必须这样做:
Collections.unmodifiableSet(fruits)
是因为Set是一个接口,并且不知道要返回哪个实现?
答案 0 :(得分:2)
Groovy增强了收集方法,这意味着它已将方法添加到标准收集类中。
其中一种方法是toSet()
:
将集合转换为集合。 始终返回一个新的集,即使该集合已经是一个集。
用法示例:
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()
调用,以将Collection
返回的unmodifiableCollection
强制转换为Set
,隐式复制数据。
当您写这篇文章时:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(fruits)
返回的值已经是Set
,因此不会调用toSet()
,这意味着unmodifiableFruits
和fruits
共享数据。
这就是为什么在使用unmodifiableSet
时必须通过添加new HashSet(...)
显式复制数据的原因。
将集合传递到构造函数中时,是否使用
Collections.unmodifiableCollection()
是正确的方法?
绝对不是。 使用unmodifiableCollection()
并分配给Set
,隐式调用复制数据的toSet
复制已执行的事实。
为确保代码可读性,即,阅读该代码的任何人(包括3年以下的您自己)都将理解其功能,请使用复制构造函数编写代码以显式复制数据。
当然,除非这是代码混淆的练习,否则在这种情况下,这是一个很好的误导性技巧。