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