簡體   English   中英

Java方法中的副作用

[英]Side effects in Java methods

這可能是一個微不足道的問題,但我需要澄清......有一本名為Clean Code的書說我們的方法應該很小,最好長達5-10行。 為了實現這一目標,我們需要將方法拆分為較小的方法。 例如,我們可能有someMethod()如下所示。 假設,'Example'的修改需要5行,我決定將其移動到一個單獨的方法中,在那里修改'Example'並將其返回到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;
}

我們不應該將對象傳遞給另一個方法並在那里修改它。

誰說的? 這實際上是一種很好的做法,以便以形成“配方”的方式拆分您的功能,並具有確切知道如何正確填充對象的特定功能。
不建議的(可能是您的建議誤解了這條規則的源)是定義公共API並修改參數。 用戶不會修改他們的論點,因為它會減少意外。 一個例子是將數組作為方法的參數傳遞。

正如JB Nizet評論的那樣,如果它是唯一的效果,它實際上並不是副作用,因此任何“所有副作用都不好”的一攬子聲明在這里都不適用。

不過,主要問題仍然存在:這(副作用)效果好嗎?

首先談論原則,副作用通常是危險的,原因有兩個:

  • 他們使並發更加困難
  • 它們模糊/隱藏信息

在您的示例中,有一些隱藏的信息。 您可以將此稱為潛在的副作用,並且可以通過以下問題公開:“這個doSomethingHere方法是創建新對象還是修改我傳入的對象?” 答案很重要,如果它是一種公共方法,那就更是如此。 通過閱讀doSomethingHere方法找到答案應該是微不足道的,特別是如果你保持你的方法'干凈',但信息仍然隱藏/模糊。

在這個特定的情況下,我會讓doSomethingHere返回void。 這樣,人們就沒有可能認為你已經創造了一個新的對象。 這只是一種個人方法 - 我相信很多開發人員都說你應該返回你修改的對象。 或者,您可以選擇一個“好的”方法名稱。 “modifyExampleInPlace”或“changeSomeFieldsInPlace”是您的特定示例imo的非常安全的名稱。

當您定義一個對象並將其傳遞給另一個方法時,方法本身可以修改其中的對象的內容,這在某些情況下可能是不需要的。 這是因為您將對象的引用(淺拷貝)傳遞給該方法,並且方法可以修改該對象。

例如,當您傳遞一個數組,數組是對象時,對於一個方法,方法可以改變數組的內容,這可能不是調用者方法所期望的。

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的深層副本發送到另一個故事的方法
但是當你使用primite類型(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM