Java 在void方法中更改值或返回新对象,哪种方法是正确的?
当您需要修改地图/列表或对象时,您更喜欢哪一种方法,哪一种方法更好Java 在void方法中更改值或返回新对象,哪种方法是正确的?,java,immutability,Java,Immutability,当您需要修改地图/列表或对象时,您更喜欢哪一种方法,哪一种方法更好 维护 在处理无效方法或新对象创建时,是否存在维护困难 成本 是的,新的对象创建仍在功能范围内,将可供GC使用,但如果我们在整个项目中这样做,想知道它会对应用程序产生怎样的影响,从一些有经验的人那里听到可能会很好 可测试性 使用void方法很难在调用方法中进行测试,但是如果能听到关于void和new的想法,那就太好了 健壮性 使用一种新的方法似乎可以避免副作用,而且更可靠。你的想法是什么 假设我有一个从方法返回
- 维护
- 在处理无效方法或新对象创建时,是否存在维护困难
- 成本
- 是的,新的对象创建仍在功能范围内,将可供GC使用,但如果我们在整个项目中这样做,想知道它会对应用程序产生怎样的影响,从一些有经验的人那里听到可能会很好
- 可测试性
- 使用void方法很难在调用方法中进行测试,但是如果能听到关于void和new的想法,那就太好了
- 健壮性
- 使用一种新的方法似乎可以避免副作用,而且更可靠。你的想法是什么
public Map<Integer, User> getUsers() {
Map<Integer, User> names = getNames();
return names;
}
publicmap getUsers(){
映射名称=getNames();
返回姓名;
}
所以在同一个函数中,我需要为它们添加前缀
public Map<Integer, User> getUsers() {
Map<Integer, User> names = getNames();
addPrefixes(names);
return names;
}
publicmap getUsers(){
映射名称=getNames();
添加前缀(名称);
返回姓名;
}
从不变性的角度来看,哪一个更好?我应该这样做吗
public Map<Integer, User> getUsers() {
Map<Integer, User> names = getNames();
Map<Integer, User> prefixedNames = getPrefixed(names);
return prefixedNames;
}
publicmap getUsers(){
映射名称=getNames();
Map prefixedNames=getPrefixed(名称);
返回前缀名称;
}
如果是这样,如何实现getPrefixed函数,深度复制每个用户并将其添加到新地图并返回,您能举个例子吗?让我们看看代码:
public Map<Integer, User> getUsers() {
Map<Integer, User> names = getNames();
// addPrefixes or names=getPrefixes
return names;
}
现在是复制的时候了,因为任何用户都可能损坏对象的状态。但是,即使getNames
是私有字段并返回内部字段,如果有人调用getUsers
(一次、两次,…),会发生什么情况?前缀将添加到内部字段中
因此,我假设getNames
返回名称的副本(例如,从数据库检索)。局部变量names
是您的,是名称的工作副本
现在,您有三种选择:
void addPrefixes(Map<Integer, User> names) { // 1
// update names
}
Map<Integer, User> getPrefixed(Map<Integer, User> names) { // 2
// update names
return names;
}
Map<Integer, User> getPrefixed(Map<Integer, User> names) { // 3
// create copy, e.g. use Java8 stream;
return namesCopy;
}
作者:
成本
如果功能是应用程序的瓶颈,则可以从选项3(更安全)开始,然后切换到选项2(带注释)。方案1和方案2的成本相同
测试性
如果需要测试前缀是否正确添加,请将getPrefixed
作为小型前缀器
类的公共方法(单一责任原则)
健壮性
选项3是最好的。如果修改getNames
以返回内部字段,会发生什么情况。例如:
// before
public Map<Integer, User>() getNames() {
// query the db
// create the map
return names;
}
// after: the method was to slow, cache the result
public Map<Integer, User>() getNames() {
if (this.names == null) {
// query the db
// create the map
}
return this.names;
}
//之前
public Map()getNames(){
//查询数据库
//创建地图
返回姓名;
}
//之后:方法是减慢速度,缓存结果
public Map()getNames(){
if(this.names==null){
//查询数据库
//创建地图
}
返回此名称;
}
选项1和2将损坏字段名称
重要提示:无论您决定什么,都要记录您的选择:当修改参数时,您应该让用户知道,因为最初的期望(在Java中)是参数不会被修改。如果函数返回副本,请让用户知道。是
getNames()
方法public
?(是的,这会影响我的答案。)这要看情况而定。现在还不清楚你的具体情况。改变空洞函数中的状态会产生副作用,并可能增加复杂性,特别是在并行计算中。创建新对象并通过函数返回它可以避免线程之间的依赖关系,但可能会降低性能,特别是在单线程情况下。关于访问器方法:我认为将内部集合作为不可变的方式返回是很好的,“如果”公开内部集合是必需的:<代码>返回集合。代码>如果多次调用getUsers(),数据是否正确?如果您不使用不变性,恐怕会在名称后面附加多个前缀
return getPrefixed(names);
return prefixer.getPrefixed(names);
// before
public Map<Integer, User>() getNames() {
// query the db
// create the map
return names;
}
// after: the method was to slow, cache the result
public Map<Integer, User>() getNames() {
if (this.names == null) {
// query the db
// create the map
}
return this.names;
}