【问题标题】:Is mutating object-parameters in a method(in Java) a bad practice?在方法中(在 Java 中)改变对象参数是一种不好的做法吗?
【发布时间】:2018-08-28 14:01:17
【问题描述】:

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

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

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。

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

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

问候 马弗林

【问题讨论】:

  • 理想情况下,您不应该修改作为参数传递的对象,除非您非常清楚这是预期的,例如modifyList 应该会修改列表。
  • @AndyTurner @throws UnsupportedOperationException - if list does not support the add operation :-)
  • @assylias 并且不尝试它就无法知道它是否会抛出它。
  • @AndyTurner Collection 的合同规定add 如果不支持操作,则必须抛出 UOE。
  • @assylias 但如果不调用add,您将无法知道List 的给定实例是否支持add。你所能做的就是捕捉异常,并希望你有失败的原子性。

标签: java copy dplyr method-parameters


【解决方案1】:

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

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

例如,JDK 中的this method 对现有列表进行了变异,但其意图和文档非常明确。

【讨论】:

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

这取决于您的用例,正如您已经暗示的那样。让你的组件不可变带来很多好处,例如更好的封装线程安全避免无效状态等。当然,这样你实施性能打击。但是有经验的人写了一章关于这个,我只能推荐:

Effective Java -

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

他建议:

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

还有:

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

【讨论】:

  • 我认为你搞错了:被调用的方法不是客户端。您的方法是破坏(或不)不变量的方法。
  • 这条评论是关于答案还是问题? (我很困惑)这取决于指出客户的角度。 Bloch 举了一个使用两个日期来实现 Period 的例子。客户端是使用 Period 对象的类。如果你的 Period 类设计得不好,你最终会让客户误用你的逻辑(因为你允许他们这样做)。
  • @EiriniGraonidou 打破不变意味着:您允许客户端修改您的类的内部状态并将其带入不一致的状态。在 op 的示例中,类的内部状态未公开 - 该方法实际上可能是 static
  • @assylias,现在我明白什么意思了。我想我一般指的是类设计级别的不变性。另一方面,我现在可以看到,需要在一个方法中本地执行此操作的范围非常小。如果您认为此答案具有误导性,请告诉我。
猜你喜欢
  • 2017-05-06
  • 1970-01-01
  • 2011-08-06
  • 2014-01-17
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多