Java 中可選的記錄參數
一、簡介
在本教程中,我們將討論使用Optional
作為記錄參數的可能性以及為什麼這是一個不好的做法。
2. Optional
用途
在討論Optional
和記錄之間的關係之前,讓我們先快速回顧一下Java中Optional
的預期用途。
通常,在 Java 8 之前,我們會使用null
來表示物件的空狀態。但是,作為傳回值的null
需要呼叫者程式碼在執行時進行null
檢查驗證。如果呼叫者未驗證,則可能會收到NullPointerException
。獲取異常有時用於識別價值的缺失。
Optional
的主要目標是表示一個方法傳回值,該值表示不存在值。我們可以使用Optional
作為傳回值,而不是讓我們的應用程式因NullPointerException
而崩潰來識別值的缺失。因此,我們在編譯時知道返回值包含某些內容或不包含任何內容。
此外,正如Java 文件中所說:
Optional 旨在為庫方法返回類型提供一種有限的機制,其中明確需要表示“無結果”,並且使用
null
極有可能導致錯誤
因此,也必須注意Optional
不打算做什麼。在這一點上,我們可以強調, Optional
並不打算用作任何類別的實例字段。
3. Java 記錄的用例
我們也來看看有關記錄的一些概念,以便為使用Optional
作為record
參數打下更好的基礎。
記錄只是一個資料持有者。當我們想要將資料從一個地方傳輸到另一個地方(例如從資料庫到我們的應用程式)時,它非常適合。
讓我們解釋一下JEP-395 :
記錄是充當不可變資料的透明載體的類別。
記錄的一個關鍵定義是它們是不可變的。因此,一旦我們實例化一筆記錄,它的所有資料在程式的其餘部分中都保持不可修改。這對於傳輸資料的物件來說非常有用,因為不可變物件不太容易出錯。
記錄也會自動定義具有相同欄位名稱的存取器方法。因此,透過定義它們,我們可以得到與定義欄位相同的 getter。
JDK 記錄定義也建議記錄所保存的資料應該是透明的。因此,如果我們呼叫訪問器方法,我們應該獲得有效的資料。在這種情況下,有效資料意味著真正代表物件狀態的值。讓我們來解釋一下琥珀計劃:
資料類別(Record)的 API 對狀態、整個狀態以及除了狀態之外什麼都沒有建模。
不變性和透明度是捍衛記錄不得具有Optional
參數這一論點的基本定義。
4. 可選作為記錄參數
現在我們對這兩個概念有了更好的理解,我們將了解為什麼必須避免使用Optional
作為記錄參數。
首先,我們定義一個記錄範例:
public record Product(String name, double price, String description) {
}
我們已經為產品定義了一個資料持有者,其中包含name, price,
和description.
我們可以想像由資料庫查詢或 HTTP 呼叫產生的資料持有者。
現在,我們假設有時未設定產品描述。在這種情況下, description
可以為空。解決這個問題的一種方法是將description
欄位包裝到Optional
物件中:
public record Product(String name, double price, Optional<String> description) {
}
儘管上面的程式碼編譯正確,但我們破壞了Product
記錄的資料透明度。
此外,記錄不變性使得處理Optional
實例比處理null
變數更困難。讓我們透過一個簡單的測試來看看實際情況:
@Test
public void givenRecordCreationWithOptional_thenCreateItProperly() {
var emptyDescriptionProduct = new Product("television", 1699.99, Optional.empty());
Assertions.assertEquals("television", emptyDescriptionProduct.name());
Assertions.assertEquals(1699.99, emptyDescriptionProduct.price());
Assertions.assertNull(emptyDescriptionProduct.description().orElse(null));
}
我們創建了一個具有一些值的Product
,並使用產生的 getter 來斷言記錄實例化正確。
在我們的產品中,我們定義了變數name
、 price
和description
。但是,由於description
是Optional
,因此我們在檢索它後不會立即獲得值。我們需要做一些邏輯來打開它來取得值。換句話說,我們在呼叫訪問器方法後並沒有獲得正確的物件狀態。因此,它打破了Java記錄的資料透明度的定義。
我們可能會想,既然如此,我們該如何處理null
呢?好吧,我們可以簡單地讓它們存在。 null
表示物件的空狀態,在這種情況下比空的Optional
實例更有意義。在這些場景中,我們可以透過使用@Nullable
註解或其他處理null
良好實踐來通知Product
類別的使用者description
可以為空。
由於記錄欄位是不可變的, description
字段無法更改。因此,要檢索description
值,我們有一些選擇。一種是使用orElse
() 和orElseGet()
開啟它或傳回預設值。另一種方法是盲目地使用get()
,如果沒有值,它會拋出NoSuchElementException
。第三種是如果內部沒有任何內容,則使用orElseThrow()
拋出錯誤。
在任何可能的處理方式中, Optional
都沒有任何意義,因為在任何情況下,我們要么返回null
要么拋出錯誤。讓description
為可為空的String
會比較簡單。
5. 結論
在本文中,我們了解了 Java 記錄的定義並了解了透明度和不變性的重要性。
我們也研究了Optional
類的預期用途。更重要的是,我們討論了Optional
不適合用來當作記錄參數。
與往常一樣,您可以在 GitHub 上找到原始程式碼。