偵錯便利性
您程式庫的使用者會基於其功能進行建置,而他們建置的功能可能會包含需要識別與解決的錯誤。 此錯誤解決過程可能會在開發期間透過偵錯工具進行,或是在正式環境中使用日誌與觀測性工具。 您的程式庫可以遵循以下最佳實務,讓偵錯變得更容易。
為具狀態型別提供 toString 方法
針對每個包含狀態的型別,請提供有意義的 toString 實作。 此實作應傳回該執行個體目前內容的清晰表示,即使是內部型別也是如此。
由於型別的 toString 表示通常會寫入日誌,實作此方法時請考量安全性,並 避免傳回敏感的使用者資料。
確保描述狀態的格式在程式庫中的不同型別間盡可能保持一致。 當此格式作為 API 實作契約的一部分時,應對其進行明確描述與完整文件化。 toString 方法的輸出可能支援剖析,例如在自動化測試套件中。
例如,考慮以下來自支援服務訂閱程式庫的型別:
enum class SubscriptionResultReason {
Success, InsufficientFunds, IncompatibleAccount
}
class SubscriptionResult(
val result: Boolean,
val reason: SubscriptionResultReason,
val description: String
)若沒有 toString 方法,列印 SubscriptionResult 執行個體並不實用:
fun main() {
val result = SubscriptionResult(
false,
IncompatibleAccount,
"Users account does not support this type of subscription"
)
//印出 'org.example.SubscriptionResult@13221655'
println(result)
}偵錯工具中也不會直接顯示該資訊:

加入簡單的 toString 實作後,在兩種情況下的輸出都能顯著改善:
//印出 'Subscription failed (reason=IncompatibleAccount, description="Users
// account does not support this type of subscription")'
override fun toString(): String {
val resultText = if(result) "succeeded" else "failed"
return "Subscription $resultText (reason=$reason, description=\"$description\")"
}
雖然使用資料類別來自動取得 toString 方法可能很有吸引力,但基於回溯相容性的考量,不建議這樣做。 資料類別會在 在您的 API 中避免使用資料類別 章節中進行更詳細的討論。
請注意,toString 方法中描述的狀態不一定非得是問題領域的資訊。 它可以與進行中請求的狀態(如上述範例)、連線至外部服務的健全狀況, 或是進行中作業的過渡狀態有關。
例如,考慮以下產生器型別:
class Person(
val name: String?,
val age: Int?,
val children: List<Person>
) {
override fun toString(): String =
"Person(name=$name, age=$age, children=$children)"
}
class PersonBuilder {
var name: String? = null
var age: Int? = null
val children = arrayListOf<Person>()
fun child(personBuilder: PersonBuilder.() -> Unit = {}) {
children.add(person(personBuilder))
}
fun build(): Person = Person(name, age, children)
}
fun person(personBuilder: PersonBuilder.() -> Unit = {}): Person =
PersonBuilder().apply(personBuilder).build()這是您會使用此型別的方式:

如果您在上方圖片顯示的中斷點處停止程式執行,顯示的資訊將毫無幫助:

加入簡單的 toString 實作會產生更有幫助的輸出:
override fun toString(): String =
"PersonBuilder(name=$name, age=$age, children=$children)"加入後,偵錯工具會顯示:

如此一來,您可以立即查看哪些欄位已設定,哪些尚未設定。
採用並文件化處理例外的政策
正如 選擇適當的錯誤處理機制 章節中所討論的, 在某些情況下,您的程式庫適合透過拋出例外來發出錯誤訊號。 您可以為此目的建立自己的例外型別。
抽象化並簡化底層 API 的程式庫也需要處理其相依項拋出的例外。 程式庫可以選擇隱藏例外、按原樣傳遞、將其轉換為不同的例外型別, 或是以不同的方式向使用者發送錯誤訊號。
根據上下文,這些選項都可能是有效的。例如:
- 如果使用者採用程式庫 A 純粹是為了簡化程式庫 B,那麼程式庫 A 在不進行修改的情況下重新拋出程式庫 B 產生的任何例外可能是合適的。
- If library A adopts library B purely as an internal implementation detail, then library-specific exceptions thrown by library B should never be exposed to users of library A.
- 如果程式庫 A 採用程式庫 B 純粹是作為內部的實作細節,那麼程式庫 B 拋出的特定程式庫例外絕不應暴露給程式庫 A 的使用者。
您必須採用並文件化一致的例外處理方法,以便使用者能有效地利用您的程式庫。 這對於偵錯尤為重要。您程式庫的使用者應該能夠在偵錯工具和日誌中,識別出 例外是否源自於您的程式庫。
例外的型別應指出錯誤的類型,且例外中的資料應協助使用者定位 問題的根本原因。 一種常見的模式是將底層例外包裝在特定於程式庫的例外中,並透過 cause 存取原始例外。
下一步
在指南的下一部分中,您將學習測試便利性。
