簡體   English   中英

為什么在 Java 類中存儲計算值是不好的做法,我該如何避免?

[英]Why is it bad practice to store calculated values in Java classes, and how can I avoid it?

我是 Java 新手,我正在攻讀該語言的研究生課程。 才過了幾個星期。 我回到了一個我剛剛工作的實驗室,教授告訴我“我們不會在我們的課程中存儲計算值”,並向我推薦了最佳實踐文檔。 我查看了文檔,但沒有看到對計算值的引用。

我認為他指的是這段代碼:

public double getCalories() {
    this.calories = (((this.weight * 0.12) * 9) + ((this.weight * 0.09) * 4)
            + ((this.weight * 0.02) * 4));
    return this.calories;
}

我不得不使用重量來計算卡路里的數量。 這是我在這門課上做的唯一真正的計算,所以我認為這就是問題所在。 有沒有更好的方法來寫這個? 那么如何進行計算呢?

您必須詢問您的教授,這並不是“Java 的注意事項”列表中的最前面和中間位置。 但是,對於您的特定代碼段,您的教授可能會略有不同:

你在這里做的事情絕對沒有任何目的,或者,如果有,你的代碼就被破壞了。

只有兩種選擇:

  1. 這是整個代碼庫中唯一一個引用calories字段的地方,或者

  2. 還有其他地方可以使用該字段。

選項 1 - 這是您唯一使用它的地方。

然后就沒用了。 每次有人調用getCalories(),您都會計算卡路里。 Java 不是巫術; 如果一個方法被調用,它的每一行都按順序執行。 添加一個這樣的字段......也意味着java會將結果存儲在該字段中。 不代表java下次會跳過計算!

因此,您的getCalories()調用將進行計算、存儲結果並返回結果。 存儲的結果不會在任何地方使用,完全浪費空間。 修復:只是..不要存儲它。 刪除該字段。 使該方法成為 oneliner(將this.calories =替換為return

選項 2 - 您在其他地方使用它

假設你在這個類中有另一個方法:

public boolean exceedsRecommendedDaily() {
    return this.calories > 2000;
}

那么這段代碼就被破壞了——如果我調用這個方法,那么卡路里字段仍然是 0 並且將保持為 0,直到有人調用getCalories() 我想我們可以通過記錄這種行為來修復它,如下所示:

/**
 * Calculates if this food item on its own exceeds recommended daily intake.
 * NB: If you haven't called `getCalories()` earlier on this object,
 * this method will straight up lie to you!
 */

但我認為我們都同意這意味着該方法是愚蠢的。

不,為什么不這樣做:

public boolean exceedsRecommendedDaily() {
    return getCalories() > 2000;
}

多田。 不再需要愚蠢的警告。

那么..這是最佳實踐嗎?

不它不是。 如果計算需要足夠長的時間,並且經常需要計算結果,並且對象是不可變的(沒有設置方法/構造后沒有任何字段可以更改)或者每次字段更新都值得清除緩存的值,那么緩存該值是個好主意。

例如,java 自己的java.lang.String緩存了哈希碼,因為計算它是一個相當昂貴的操作(它至少需要檢查每個字符。所以在一個 100 萬個字符的字符串中,這需要一段時間!),它可以被稱為噸,字符串是不可變的。

您的函數計算卡路里並返回計算值。 您發布的代碼中沒有理由存儲返回值的副本; 它無處使用。

public double getCalories() {
    return (((this.weight * 0.12) * 9) + ((this.weight * 0.09) * 4)
            + ((this.weight * 0.02) * 4));
}

如果碰巧有其他代碼(未顯示)使用 this.calories 的值,那么 getCalories 方法就有另一個缺陷。 它被稱為“getCalories”,如果它為其他方法節省了值,這令人驚訝; 如果不先調用 getCalories,則其他方法可能會發生故障。

“我們不會在我們的類中存儲計算值”,我個人認為這個說法不清楚,因為它背后沒有上下文。 我猜你的導師意味着不要將冗余信息存儲到全局字段。

創建類的時候,由於不同的原因,你要把數據封裝在里面,詳細可以看OOP語言的概念。 在您的情況下,您的班級持有實體的信息。

例如:

class car {
  int engineVersion
  String modelName
}

你看, engineVersionmodelName是對象car modelName的重要信息,方便以后訪問。 當您存儲信息時,它肯定會花費空間。 但是,對於您的方法getCalories ,假設您自己的類不需要它(即:不在其他地方使用它),您可以直接返回結果,然后您可以節省資源。

你的“教授”是錯誤的:沒有“最佳實踐”來管理這個。

答案是“視情況而定”。

如果計算很昂貴,請考慮存儲它,但是如果狀態發生變化,您將需要在 setter 中使用鈎子來使計算無效。 這是一種緩存形式。 它使類有些復雜,但可以安全地完成並且如果為了性能而犧牲簡單性是可以接受的,則是合理的。

如果類是immutable ,則無需擔心狀態更改,因此您可以計算它,理想情況下是惰性的(即按需),一次並存儲該值而無需任何此類掛鈎。

如果計算成本低,則每次都進行計算會更清晰。

暫無
暫無

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

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