Java方法中的副作用

时间:2017-07-10 17:52:48

标签: java

这可能是一个微不足道的问题,但我需要澄清...... 有一本名为Clean Code的书说我们的方法应该很小,最好长达5-10行。为了实现这一目标,我们需要将方法拆分为较小的方法。 例如,我们可能有someMethod()如下所示。让我们来说,修改'示例'需要5行,我决定将其移到一个单独的方法中,修改'示例'在那里并将其返回到someMethod()。通过这样做,someMethod()变得更小,更容易阅读。那很好,但是有一种叫做副作用的东西"这表示我们不应该将对象传递给另一个方法并在那里修改它。至少,我被告知这是一个坏主意)但我还没有看到任何禁止我在清洁代码中这样做的事情。

public Example someMethod() {

    // ... different lines here

    Example example = new Example();
    example = doSomethingHere(example, param1, param2, ...);    

    // ... different lines here

    return example;
}

private Example doSomethingHere(Example example, 'some additional params here') {

    // ... modify example's fields here ...

    return example;
}

那么,我是否允许以这种方式拆分方法或禁止这样的副作用,而是应该采用一种相当长的方法,这种方法肯定会破坏清洁代码关于简短方法的规则?

更新(子方法的更具体名称)

public Example someMethod() {

    // ... different lines here

    Example example = new Example();
    example = setExampleFields(example, param1, param2, ...);    

    // ... different lines here

    return example;
}

private Example setExampleFields(Example example, 'some additional params here') {

    // ... modify example's fields here ...

    return example;
}

3 个答案:

答案 0 :(得分:4)

  

我们不应该将对象传递给另一个方法并在那里进行修改。

谁说的?这实际上是一种很好的做法,以便以一种形成"配方的方式分割你的功能。并具有确切知道如何正确填充对象的特定功能 不建议的(可能是您的建议误解了这条规则的源)是定义公共API并修改参数。用户不会修改他们的论点,因为它会减少意外。一个例子是将数组作为方法的参数传递。

答案 1 :(得分:3)

正如JB Nizet评论的那样,如果它是唯一的副作用,它实际上并不是副作用,所以任何一揽子声明,即所有副作用都不好"不适用于此。

然而,主要问题是:这(副作用)效果好吗?

首先谈论这些原则,副作用通常是危险的,原因有两个:

  • 他们使并发更加困难
  • 他们隐藏/隐藏信息

在您的示例中,有一些隐藏的信息。您可以将此称为潜在的副作用,并且可以通过以下问题公开:"这个doSomethingHere方法是否创建了一个新对象或修改了我传入的对象?" 答案很重要,如果它是一种公共方法,那就更是如此。 通过阅读doSomethingHere方法找到答案应该是微不足道的,特别是如果你保持你的方法“干净”,但信息仍然隐藏/模糊。

在这种特定情况下,我会让doSomethingHere返回void。这样,人们就没有可能认为你已经创造了一个新的对象。 这只是一种个人方法 - 我确信很多开发人员都说你应该返回你修改的对象。 或者,你可以选择一个好的'方法名称。 " modifyExampleInPlace"或者" changeSomeFieldsInPlace"对于您的具体示例,imo。

是非常安全的名称

答案 2 :(得分:0)

当您定义一个对象并将其传递给另一个方法时,方法本身可以修改其中的对象内容,这在某些情况下可能是不需要的。这是因为您将对象的引用(浅拷贝)传递给该方法,并且方法可以修改该对象。
例如,当您传递一个数组时,数组是对象,方法,方法可以更改数组的内容,这可能不是调用方法所期望的内容。

public static void main(String[] args){
  int a= 1
  y(a);
  //After the method a is not changed
}
public void y(int comingInt){
  comingInt = 5;
}

为确保无法更改Array的值,应将Array的深层副本发送到另一个故事的方法
但是,当您使用primite类型(int,float等)

时,情况并非如此
{{1}}

由于对象的性质,您应该小心。要了解有关浅拷贝和深拷贝的更多信息https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm