平時無人在意 toString() 效能,直到大批量日誌輸出導致系統卡頓。本文基於 JMH (Java Microbenchmark Harness) 實測,對比 7 種主流實現方式,揭示效能真相。
| 排名 | 實現方式 | 平均吞吐量 (ops/s) | 相對效能 | 特點 |
|---|---|---|---|---|
| 🥇 1 | + 拼接 | 1,420,751 | 100% (基準) | JVM 優化為 StringBuilder,最快、最簡潔 |
| 🥈 2 | StringBuilder 手寫 | 1,414,634 | 99.6% | 手動控制,效能持平 + 拼接 |
| 🥉 3 | Objects.toString() | 1,407,913 | 99.1% | JDK 7+ 內建,自動處理 null,推薦生產使用 |
| 4 | Guava Objects.toStringHelper | 1,101,118 | 77.5% | 鏈式 API 優雅,但有額外開銷 |
| 5 | Commons Lang ToStringBuilder (append) | 751,655 | 52.9% | 手動 append,比反射快一倍 |
| 6 | ToStringBuilder.reflectionToString | 349,306 | 24.6% | 反射掃描字段,顯著拖慢 |
| 7 | ReflectionToStringBuilder | 232,044 | 16.3% | 最慢,純反射實現,慎用於高頻場景 |
public String toString() {
return "MyObject{" +
"att1='" + att1 + '\'' +
", att2='" + att2 + '\'' +
", att3='" + att3 + '\'' +
"} " + super.toString();
}
public String toString() {
return "MyObject{" +
"att1='" + Objects.toString(att1) + '\'' +
", att2='" + Objects.toString(att2) + '\'' +
", att3='" + Objects.toString(att3) + '\'' +
"} " + super.toString();
}
優勢:原生 JDK、自動處理 null、效能幾無損耗。
public String toString() {
StringBuilder sb = new StringBuilder("MyObject{");
sb.append("att1='").append(att1).append('\'');
sb.append(", att2='").append(att2).append('\'');
sb.append(", att3='").append(att3).append('\'');
sb.append(super.toString());
return sb.toString();
}
public String toString() {
return Objects.toStringHelper(this)
.add("att1", att1)
.add("att2", att2)
.add("att3", att3)
.add("super", super.toString())
.toString();
}
// 5. 手動 append (尚可)
new ToStringBuilder(this)
.append("att1", att1)
.append("att2", att2)
.append("att3", att3)
.toString();
// 6. reflectionToString (慢)
ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
// 7. ReflectionToStringBuilder (最慢)
ReflectionToStringBuilder.toString(this);
Objects.toString(): 唯一兼顧 效能、null 安全、零依賴 的方案。Objects.toString() 或 + 拼接。只有當
toString()處於 高頻調用熱點 (大批量日誌、序列化、監控採集) 時,效能差異才轉化為可觀的 CPU/延遲節省。常規業務代碼,可讀性優先。
測試代碼與完整 JMH 報告歡迎交流探討。下期預告:equals()/hashCode() 效能避坑指南。