2014-04-19 24 views
2

Effective Java - Item-2 states 期間不一致,的JavaBean缺點 - 施工

一個JavaBean可以是不一致的狀態在中途經過它的結構。

我不明白這一點,如果對象是一個方法的構建,怎麼會是去不一致的,如果有異常發生,可以在構造函數中出現過。這與線程有什麼關係?

+0

在閱讀本書中的特定句子時,我只是放棄了點燃,並在這裏搜索到了相當快的方式。我相信,雖然關注的範圍不僅僅涉及線程,但在構建多線程使用的對象時觀察這種行爲將更爲常見,除非確保沒有人特意在構建器之間構建構造。 – mass

回答

3

以下豆是在書中提出:

NutritionFacts cocaCola = new NutritionFacts(); 
cocaCola.setServingSize(240); 
cocaCola.setServings(8); 
cocaCola.setCalories(100); 
cocaCola.setSodium(35); 
cocaCola.setCarbohydrate(27); 
這些

,通過setServingSize(int)setServings(int)設置servingSizeservings是基本的 - 至少在這本書 - 爲營養成分。

但如果你只需要調用:

NutritionFacts cocaCola = new NutritionFacts(); 
cocaCola.setServingSize(240); 
cocaCola.setCalories(100); 

那麼servings外地也不用設置。因此得到的實例現在處於無效狀態。

因此,如果您要調用一個期望有效實例的方法,比如說healthRiskCalculator.calculateHealthRisk(NutritionFacts facts),那麼您將在對象內或healthRiskCalculator中收到異常。

因此,現在您可以在致電calculateHealthRisk()時檢查對您健康的損害,但可能有許多讀取或使用對象實例的方法。此外,您也可能爲其他產品創建了大量無效實例。換句話說,這不是快速失敗

所以沒有使用bean創建構造對象的失敗安全方法。這不是線程特有的,你可以在一個線程中創建一個無效的bean實例。

+1

正在經歷這一次,它讓我思考。如果我爲構造函數提供強制性參數會怎麼樣?我猜代碼會偏離JavaBeans模式,但它仍然可以工作,對吧? – Batty

+0

當然,當我製作實例時,我一直都在做。如果構造函數變得太複雜,那麼你可以使用工廠方法甚至對象工廠。 –

+0

同意Batty就是這樣,一個帶有強制參數的構造函數以及setter調用可選參數的構造函數也應該可以很好地工作。 –

1

想象一個線程模型,其中ThreadUtils.doFoo(FooBean fb)會產生一個可與fb一起使用的線程。 fb可以像傳遞給該線程的參數一樣簡單以定義其計算。現在,採取以下構造:

public FooBean(int i, int j, int k, int l, int port){ 
    ThreadUtils.doFoo(this); 
    someListField = Arrays.asList(i, j, k, l); 
    this.port = port; 
} 

這將導致this泄漏出來的構造。如果出於某種虛假原因,生成的線程在列表正確實例化和分配之前發揮作用,您將有一個線程處理this的不一致狀態。例如,如果新線程使用port偵聽套接字,並且this泄露,套接字可能偵聽端口0(數值字段的默認值),而不是端口port

事實上,如果this泄漏並從其他地方獲得強引用,構造函數中的異常可能會成爲問題。

但是,下面的構造是安全的:

public FooBean(int i, int j, int k, int l, int port){ 
    someListField = Arrays.asList(i, j, k, l); 
    this.port = port; 
    ThreadUtils.doFoo(this); 
} 

這是因爲在Java內存模型,線程甚至被催生之前的字段存儲。

+1

@owlstead也許是因爲這個問題問「這和線程有什麼關係?」 –

+0

@MattCoubrough本章懷疑自己的線程無效。此外,這個bean示例着重介紹了setter,這些不在hexafractions示例中。 –