之前出了一個視頻,介紹 JDK 23 中的新特性。之后我才發現,在 JDK 21 和 22 中的預覽功能“字符串模板(String Templates)”,在 JDK 23 中已經沒有了。字符串模板的相關代碼,已經被全部刪除了。
字符串模板的功能,Java 社區已經期待太久了。其他主流的編程語言,都提供了字符串插值的功能。Java 語言一直沒有,也確實說不過去。JDK 21 中字符串模板的出現,解決了這一長期問題。JDK 23 直接把字符串模板刪除,確實有點突然。
至于為什么要刪掉字符串模板,這個功能的開發者給出的理由是:字符串模板的當前設計存在一些問題,但是具體要怎么改,又缺乏足夠的共識,所以就直接先刪掉了。等再收集一些反饋,達成了足夠的共識之后,再把字符串模板加回來。
關于字符串模板設計上的問題,Brian Goetz 寫了一段很長的文字來說明,感興趣的人可以看原文。
總的來說,現在的字符串模板的處理器的設計過于復雜,完全沒有必要。說到這里,我們再回顧一下字符串模板的設計,具體的內容可以看我之前的視頻。這里簡單地說一下。
字符串模板用 StringTemplate 來表示,一個字符串模板中可以包含表達式,比如,My name is \{name} 是一個字符串模板,其中 name 是表達式。StringTemplate.Processor 接口,把 StringTemplate 對象轉換成其他任意類型對象。內置的 Processor 實現 STR,把 StringTemplate 轉換成 String,也就是進行字符串插值。
Processor 設計的出發點是允許創建自定義的轉換器,把 StringTemplate 安全地轉換成其他類型的對象。舉例來說,可以創建一個名為 DB 的處理器,把 StringTemplate 轉換成 JDBC 中的 PreparedStatement。但是轉換成 PreparedStatement 并不是終點,實際的目的是執行 PreparedStatement,獲取數據庫查詢的結果。DB 處理器的一般使用方式類似下面這樣。這段代碼會被添加在數據庫查詢類的某個方法中。
var stmt = DB."";
stmt.executeQuery();
對于這樣的使用方式,完全可以去掉 Processor 的實現,把 Processor 的實現代碼直接添加到當前類中。當前方法改為接受一個 StringTemplate 類型的參數。修改之后的代碼如下所示。
ResultSet query(StringTemplate template) {var stmt = ; // DB 處理器的代碼實現return stmt.executeQuery();
}
新的實現完全去掉了 Processor 的實現類,更容易理解。當前的數據庫查詢類,很可能已經有一個 String 類型的參數來表示 SQL 語句,再添加一個 StringTemplate 類型的參數,從接口上來說很容易理解和使用。
ResultSet query(String sql)
ResultSet query(StringTemplate template)
另外一個例子是解析 JSON 字符串的 JSON 處理器,與其使用 StringTemplate 的Processor,還不如在解析 JSON 的類中,添加一個新的 parse 方法,參數是 StringTemplate。這樣在實現上更緊湊。
<T> T parse(StringTemplate template, Class<T> type)
總的來說,雖然 Processor 接口設計的出發點是好的,但是在實際使用中卻是多余的。
這里分成兩種情況,第一種情況是 Processor 產生的是最終的結果,需要被外部消費。這一類場景通常是把某種類型格式的字符串表示,解析成對象形式。如 JSON 和 XML 的解析。這一類的 Processor 實現,看似有一定的通用性,實際上,只需要在已有的 JSON 或 XML 的解析類上,添加一個以 StringTemplate 作為參數的方法即可。這樣更符合解析庫使用者的使用方式。
第二種情況是 Processor 產生的是中間結果,還需要后續的處理。這一類場景通常是使用字符串作為輸入,解析之后再進一步處理。典型的例子是上面介紹的數據庫查詢。Processor 的處理結果,并不會單獨拿出來使用。對于這一類情況,同樣可以添加一個以 StringTemplate 為參數的方法。使用 Processor 來實現實屬多此一舉,Processor 實現被復用的可能性也比較低。
綜上所述,把 StringTemplate 單獨拿出來使用就足夠了,Processor 接口實際上是多余的。
字符串模板因為設計上的問題,短時間內無法達成一致,被從 JDK 23 中刪除了。刪除的主要原因,是為了避免有更多的代碼使用這一有瑕疵的設計,導致以后修改起來更困難。
JDK 中的預覽功能,其出發點是為了對新的想法進行試驗,并獲取反饋。所以預覽功能被刪除,從流程上來說是合理的。但是負面的影響仍然是很大的。
一個預覽功能,從想法的產生,到設計,再到實現,并最終出現在 JDK 中,這是一個很漫長的過程,其中所花費的成本很高。預覽功能一旦進入到 JDK,就會有人去使用它。 一個預覽功能被刪除了,使用它的代碼都需要被修改。雖然使用預覽功能是風險自負,但是在 JDK 使用者的印象中,預覽功能的穩定性是足夠的。在過往的歷史中,預覽功能可能會有小的修改,但是總體的設計和實現是穩定的。提前使用預覽功能的風險其實很低。字符串模板這個預覽功能被刪除,打破了 JDK 用戶對于預覽功能的穩定性的預期。在這之后,大家再使用 JDK 的預覽功能,積極性就會低很多,因為不確定性變高了。從結果上來說,不利于 JDK 的預覽功能獲取到足夠的反饋。
以上就是 JDK 23 中,字符串模板被刪除所相關的內容。只能說,確實很意外。不過既然已經是既成事實,用了字符串模板的應用,需要考慮今后的兼容性問題。因為最早引入字符串模板的 Java 21 是 LTS 版本,應用預計會使用這個版本運行較長時間,因此可以考慮保留已有的使用字符串模板的代碼。下一個 Java 的 LTS 版本是 Java 25,不確定字符串模板是否會在 Java 25 回歸。
點擊【閱讀原文】查看OpenJDK郵件組中關于字符串模板被刪除的原始說明。