5

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

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

public void modifyList(List<Object> list) {
    list.add(new Object());
}

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

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;
}

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

但这真的是要走的路吗?由于必须创建大量深层副本,因此性能会受到影响。此外,实现 Copy-Constructors 并为所有类实现克隆方法将花费大量时间。它也会极大地增加 LOC。

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

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

问候马弗林

4

2 回答 2

5

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

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

例如,JDK中的这个方法改变了一个现有的列表,但它的意图和文档非常清楚。

于 2018-08-28T14:13:05.447 回答
4

正如您已经暗示的那样,这取决于您的用例。使您的组件不可变带来许多优点,例如更好的封装线程安全避免无效状态等。当然,通过这种方式您实现了性能损失。但是有经验的人写了一章关于这个,我只能推荐:

有效的 Java -

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

他在那里建议:

你必须防御性地编程,假设你的类的客户会尽最大努力破坏它的不变量。

并且:

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

于 2018-08-28T14:16:38.397 回答