Java ';集合。不可修改的集合';在构造函数中
在代码审查期间,我不时看到这样的构造函数:Java ';集合。不可修改的集合';在构造函数中,java,constructor,defensive-copy,Java,Constructor,Defensive Copy,在代码审查期间,我不时看到这样的构造函数: Foo(Collection<String> words) { this.words = Collections.unmodifiableCollection(words); } Foo(集合词){ this.words=Collections.unmodifiableCollection(words); } 这是保护类的内部状态的正确方法吗?如果不是,那么在构造函数中创建适当的防御副本的惯用方法是什么?应该是这样,但这是不正确
Foo(Collection<String> words) {
this.words = Collections.unmodifiableCollection(words);
}
Foo(集合词){
this.words=Collections.unmodifiableCollection(words);
}
这是保护类的内部状态的正确方法吗?如果不是,那么在构造函数中创建适当的防御副本的惯用方法是什么?应该是这样,但这是不正确的,因为调用者仍然可以修改基础列表 不要包装清单,你应该做一份防御性的复制品,例如用番石榴代替
Foo(集合词){
if(words==null){
抛出新的NullPointerException(“单词不能为null”);
}
this.words=ImmutableList.copyOf(words);
if(this.words.isEmpty()){//示例额外前提条件
抛出新的IllegalArgumentException(“单词不能为空”);
}
}
因此,为类建立初始状态的正确方法是:
null
集合
的情况),则制作一份防御性副本。在这种情况下,因为元素类型是不可变的(String
),所以可以使用浅拷贝,但如果不是,则必须创建更深的拷贝应该是,但它不正确,因为调用方仍然可以修改基础列表 不要包装清单,你应该做一份防御性的复制品,例如用番石榴代替
Foo(集合词){
if(words==null){
抛出新的NullPointerException(“单词不能为null”);
}
this.words=ImmutableList.copyOf(words);
if(this.words.isEmpty()){//示例额外前提条件
抛出新的IllegalArgumentException(“单词不能为空”);
}
}
因此,为类建立初始状态的正确方法是:
null
集合
的情况),则制作一份防御性副本。在这种情况下,因为元素类型是不可变的(String
),所以可以使用浅拷贝,但如果不是,则必须创建更深的拷贝单词
,但这并不意味着单词
不能在其他地方修改。例如:
List<String> words = new ArrayList<>();
words.add("foo");
Collection<String> fixed = Collections.unmodifiableCollection(words);
System.out.println(fixed);
words.add("bar");
System.out.println(fixed);
如果要在不可修改集合中保留单词的当前状态,则需要从传递的集合中创建自己的元素副本,然后用集合将其包装。不可修改集合(WordScope)代码>
例如,如果您只想保留单词的顺序:
this.words = Collections.unmodifiableCollection(new ArrayList<>(words));
// separate list holding current words ---------^^^^^^^^^^^^^^^^^^^^^^
this.words=Collections.unmodifiableCollection(新的ArrayList(words));
//包含当前单词的单独列表---------^^^^^^^^^^^^^^^^^^^^^^
只创建包装器,通过它您不能修改单词
,但这并不意味着单词
不能在其他地方修改。例如:
List<String> words = new ArrayList<>();
words.add("foo");
Collection<String> fixed = Collections.unmodifiableCollection(words);
System.out.println(fixed);
words.add("bar");
System.out.println(fixed);
如果要在不可修改集合中保留单词的当前状态,则需要从传递的集合中创建自己的元素副本,然后用集合将其包装。不可修改集合(WordScope)代码>
例如,如果您只想保留单词的顺序:
this.words = Collections.unmodifiableCollection(new ArrayList<>(words));
// separate list holding current words ---------^^^^^^^^^^^^^^^^^^^^^^
this.words=Collections.unmodifiableCollection(新的ArrayList(words));
//包含当前单词的单独列表---------^^^^^^^^^^^^^^^^^^^^^^
不,这并不能完全保护它
我喜欢用这个成语来确保内容是不变的:
public Breaker(Collection<String> words) {
this.words = Collections.unmodifiableCollection(
Arrays.asList(
words.toArray(
new String[words.size()]
)
)
);
}
公共断路器(集合字){
this.words=Collections.unmodifiableCollection(
Arrays.asList(
托雷(
新字符串[words.size()]
)
)
);
}
但这里的缺点是,如果传入哈希集或树集,它将丢失速度查找。如果您关心哈希或树的特性,您可以做一些事情,而不是将其转换为固定大小的列表。不,这并不能完全保护它
我喜欢用这个成语来确保内容是不变的:
public Breaker(Collection<String> words) {
this.words = Collections.unmodifiableCollection(
Arrays.asList(
words.toArray(
new String[words.size()]
)
)
);
}
公共断路器(集合字){
this.words=Collections.unmodifiableCollection(
Arrays.asList(
托雷(
新字符串[words.size()]
)
)
);
}
但这里的缺点是,如果传入哈希集或树集,它将丢失速度查找。如果您关心哈希或树特征,您可以做一些事情,而不是将其转换为固定大小的列表。我只是集合
,不一定这是一个列表
@MichalKordas您仍然可以将其视为集合
,应该没有区别。如果确实如此,那么首先接受任何收藏都是错误的。@MichalKordas:这并没有改变biziclop的观点<代码>集合。不可修改的集合
仅包装现有集合。。。如果调用方可以修改该集合,那么您仍然没有真正保护类的内部状态。我只有集合
,不一定这是一个列表
@MichalKordas。您仍然可以将其视为集合
,这应该没有什么区别。如果确实如此,那么首先接受任何收藏都是错误的。@MichalKordas:这并没有改变biziclop的观点<代码>集合。不可修改的集合
仅包装现有集合。。。如果调用方可以修改该集合,那么您仍然没有真正保护类的内部状态。您能否建议集合的惯用构造函数应该是什么样子