在方法(Java 中)中改变对象参数是一种不好的做法吗?

Mav*_*ode 9 java copy method-parameters

我有一个关于改变方法中的方法参数(它们是对象)的问题。

我多次阅读和听到,在作为参数传入的方法中改变对象是一种不好的做法。例如:

public void modifyList(List<Object> list) {
    list.add(new Object());
}
Run Code Online (Sandbox Code Playgroud)

相反,应该复制传入的对象,应该对复制的对象执行突变,然后返回复制的对象。例如:

public List<Object> getModifiedList(List<Object> list) {
    List copy = new List<Object();
    //Make a deep copy if it would be necessary
    for(Object o : list) {
        copy.add(o.clone());
    }
    //Modify the copy
    copy.add(new Object());
    //return the copy
    return copy;
}
Run Code Online (Sandbox Code Playgroud)

我知道第二种方法产生副作用的可能性较小,因为它不会改变输入参数。

但这真的是正确的方法吗?由于必须创建大量深层副本,性能会受到影响。此外,为所有类实现复制构造函数和克隆方法会花费大量时间。它还会极大地增加LOC。

在实践中,我不经常看到这种模式(复制方法参数)。

有丰富经验的人(作为程序员/软件开发人员工作多年)可以回答这个问题吗?

问候马维林

Eir*_*dou 7

正如您已经暗示的那样,这取决于您的用例。让你的组件不可变会带来很多好处,比如更好的封装线程安全避免无效状态等。当然,通过这种方式你会降低性能。但是有丰富经验的人写了一个关于此的章节,我只能推荐:

有效的Java -

第 50 项:在需要时制作防御性副本。

他在那里建议:

您必须进行防御性编程,并假设您的类的客户将尽最大努力破坏其不变量。

并且:

总之,如果一个类具有从客户端获取或返回给客户端的可变组件,则该类必须防御性地复制这些组件。如果复制成本过高,并且类相信其客户不会不恰当地修改组件,那么防御性副本可能会被概述客户不修改受影响组件的责任的文档所取代。


ass*_*ias 5

这两种方法都很好,并且根据您的用例可能是正确的选择。只需确保以明确意图的方式命名它们并编写一些 javadoc 即可。

然后由开发人员决定是否可以更改原始列表,如果不行,则传递副本或使用不同的方法。

例如, JDK 中的此方法会改变现有列表,但其意图和文档非常明确。

  • JDK 以某种方式做某事并没有说明什么!由于“向后兼容性”,许多过时的代码和不良实践得以幸存。我认为最臭名昭著的是“Dimension”,它是一个可变对象,而理想情况下它应该是不可变的(因此像“setSize”这样的每个方法都必须制作防御性副本)。当然,这只是一个咆哮,因为参数变异方法有一些合法的情况,包括你的。 (5认同)