Java方法中的副作用

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

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

那么,我是否允许以这种方式拆分这些方法,或者禁止使用这种副作用,而应该处理一种相当长线的方法,它肯定会打破Clean Code有关短方法的规则?


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

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

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

主要问题仍然是:这(侧)效果好吗?

首先谈到这些原则,一般而言,副作用是危险的,原因有二:

  • 他们使并发更加困难
  • 他们掩盖/隐藏信息
  • 在你的例子中,有一些隐藏的信息。 你可以把它称为潜在的副作用,并且可以用一个问题暴露出来:“这个doSomethingHere方法创建一个新对象还是修改一个我传入的对象?” 答案很重要,如果是公开的方法,答案更重要。 通过阅读doSomethingHere方法来找到答案应该是微不足道的,特别是如果你保持你的方法'干净',但是这些信息仍然隐藏/模糊。

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


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

    谁说的? 实际上,这是一种很好的做法,以便以形成“配方”的方式拆分您的函数,并具有确切知道如何正确填充对象的特定函数。
    不推荐使用什么(也可能是你推荐误解这条规则的来源)是定义一个公共API并修改参数。 用户不喜欢修改它们的参数,因为它导致更少的意外。 一个例子是将数组作为参数传递给方法。


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

    例如,当你将一个数组,数组,数组传递给一个方法时,方法可以改变该数组的内容,这可能不是调用者方法所期望的。

    public static void main(String[] args){
      int[] arr= {1,2,3,4};
      y(arr);
      //After the method arr is changed
    }
    public void y(int[] comingArray){
      comingArray[0] = 10;
    }
    

    为了确保Array的值不能被改变,Array的深层拷贝应该被发送到另一个故事的方法
    然而,当你使用原始类型(int,float等)时,情况并非如此。

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

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

    链接地址: http://www.djcxy.com/p/8857.html

    上一篇: Side effects in Java methods

    下一篇: Why should Java 8's Optional not be used in arguments