基元需要走吗?
我目前正在使用JSF作為視圖技術,使用JPA作為持久層的企業應用程序。 它可能是支持bean或服務方法中的某種東西,但令我震驚:是否有充分的理由在企業應用程序中使用原語?
當我開始圍繞J2SE 1.2使用Java進行編程(或者是J2SE 5.0,或者也許是Java 2?)時,我僅在代碼中使用了原語。 當時,我認為可以依靠默認值,而不必在使用之前初始化某些東西,這很好。 當時我對包裝器并不了解太多,并且認為我沒有充分的理由進一步研究它們。
我沒有什么清楚的記憶,我何時開始使用原始包裝器,但是我確實記得JDK 1.5何時允許在原始體及其各自的原始包裝器類之間進行自動轉換,或者通常稱為自動裝箱/拆箱。 很好,因為將int傳遞給需要Integer的方法并不重要,反之亦然。 語法糖似乎使編程容易一些。
構架
即使諸如JSF和JPA之類的Java企業框架為您做了很多工作,它也暴露了依賴自動裝箱和原語的一些弱點。
這些框架依賴于原始包裝類的使用,而不是各個原始包裝類的使用。 如果使用JPA工具基于現有表創建實體,則該工具將使用變量類型的包裝器。 JSF輸入和轉換器對對象進行操作。 使用JPA,必須這樣做。 還記得原始的默認值嗎? 基元的默認值可以與數據庫中存儲的值混淆。
如果將long用作簡單的實體ID,則該實體的默認值為0L。 從技術上講0L是一個值,因此很難知道該實體是否已保留。 如果id的類型為Long ,則很容易判斷該實體是否已保留,因為id現在可以為null ,因此表示未持久的實體。
//id is long and entity is not persisted long id = entity.getId(); //value of 0L Long id = entity.getId(); //doesn’t help, still 0L//id is Long and entity is not persisted Long id = entity.getId(); //null long id = entity.getId(); //what happens here? //reference: https://keyholesoftware.com/2014/10/13/java-and-the-sweet-science/類型上下文
原始類型不能充分表達值的語義上下文。 假設我們從服務中檢索今天的溫度,并且返回的值表示度數是int 。 容易確定int度的上下文是什么?
首先,該值是以攝氏度還是華氏度表示的? 第二,如果值為0,該怎么辦? 您將不得不假設該值是實際設置的,而不是默認值0。您可能想知道為什么當服務說它為0時,它感覺像是70度外。
最好的解決方案可能是使用解析為適當值的自定義對象,而不是使用原始或什至原始包裝器。 對于代表溫度的值,我們可以創建一個華氏溫度對象。 該對象將消除對值上下文的所有懷疑。
// public class Fahrenheit { …private Integer degrees; … }Fahrenheit f = temperatureService.getDegrees(today);//當該方法期望華氏溫度時,開發人員將無法意外傳入一個攝氏溫度對象。
// … public Celsius convertDegrees(Fahrenheit f) { … }//only this would work Celsius c = temperatureService.convertDegrees(f);//使用原語作為返回值也可能是模棱兩可的。 返回一個布爾值以表示某件事是否有效不一定表示發生了什么。 通過包含更多信息,使用Result對象更具描述性。
嘲笑
盡管模擬框架可以處理基元,但是模擬框架喜歡與對象一起使用。 下面的代碼段是JMock中的Expectations類。 如下面的代碼片段所示,一些自動裝箱魔術使框架可以設置期望返回int值為6的期望。
Expectations.returnValue(Object result): context.checking(new Expectations() {{atLeast(1).of(serviceMock).getPrimitive(5);will(returnValue(6)); …. }
由于動態創建了數組對象,因此JMock似乎可以正確處理原始數組。
Expectations.returnValue(Object result): context.checking(new Expectations() {{int[] ints = { 2, 3 };atLeast(1).of(serviceMock).getPrimitives(5);will(returnValue(ints)); …. }
即使基元和基元數組與模擬框架一起使用,也感覺您未在使用真實值。 您的參數是一個int ,但是模擬框架希望您使用Integer。
思想
- 代碼項目
回顧原始包裝器的歷史,隨著時間的推移包裝器的功能不斷增強,自動裝箱/拆箱以及從其他語言的開發人員那里閱讀文章,感覺原始器可能已被排除在Java的最初實現之外。 Java是一種面向對象的語言,但是包含非對象原語。 自動裝箱功能比真正的解決方案更像創可貼。
由于企業應用程序可以訪問大量資源,因此我將其特定于企業應用程序。 該環境使創建使用諸如Integer和Fahrenheit之類的對象的描述性代碼變得更加容易。 在垃圾收集成本和堆大小很重要的受限設備中,原語很有意義,并且比對象同類具有優勢。
翻譯自: https://www.javacodegeeks.com/2015/02/do-primitives-need-to-go.html
總結
- 上一篇: 在JDK 8中连接字符串
- 下一篇: 功能工厂模式