在Java 18中,將UTF-8指定為標準Java API的預設字符集。有了這一更改,依賴於預設字符集的API將在所有實現、作業系統、區域設定和配置中保持一致。
做這一更改的主要目標:
- 當Java程式的程式碼依賴於預設字符集時,使其更具可預測性和可移植性。
- 闡明標準Java API在哪裡使用預設字符集。
- 在整個標準Java API中對UTF-8進行標準化,但控制檯I/O除外。
需要注意的是,這一更改的目標並不是定義新的標準Java API或受支援的JDK API,儘管這項工作可能會發現新的便利方法可能會使現有的API更易於使用,這一更改並不是要棄用或刪除依賴預設字符集的標準Java API。
用於讀寫檔案和處理文字的標準Java API允許將字符集作為引數傳遞。字符集控制Java程式語言的原始位元組和16位字元值之間的轉換。例如,支援的字符集包括US-ASCII、UTF-8和ISO-8859-1。
如果沒有傳遞字符集引數,則標準的Java API通常使用預設的字符集。JDK在啟動時根據執行時環境選擇預設的字符集:作業系統、使用者的區域設定和其他因素。
因為預設字符集在每個地方都不一樣,所以使用預設字符集的API會帶來許多不明顯的危險,甚至對經驗豐富的開發人員也是如此。
考慮這樣一個應用程式,它在不傳遞字符集的情況下建立一個java.io.FileWriter
,然後使用它將一些文字寫入檔案。結果檔案將包含一個使用執行應用程式的JDK的預設字符集編碼的位元組序列。第二個應用程式在不同的機器上執行,或者由同一臺機器上的不同使用者執行,在不傳遞字符集的情況下建立一個java.io.FileReader
,並使用它來讀取該檔案中的位元組。生成的文字包含使用執行第二個應用程式的JDK的預設字符集解碼的字元序列。如果第一個應用程式的JDK和第二個應用程式的JDK之間的預設字符集不同,則生成的文字可能會被損壞或不完整,因為FileReader
無法判斷它使用了相對於FileWriter
的錯誤字符集來解碼文字。
比如這就是一個典型的例子,在MacOS上以UTF-8編碼的日語文字檔案在Windows上以美英或日語區域設定讀取時被損壞:
java.io.FileReader(“hello.txt”) -> “こんにちは” (macOS)
java.io.FileReader(“hello.txt”) -> “ã?“ã‚“ã?«ã?¡ã? ” (Windows (en-US))
java.io.FileReader(“hello.txt”) -> “縺ォ縺。縺ッ” (Windows (ja-JP)
在JDK 17及更早版本中,預設字符集是在Java執行時才確定的。在MacOS上,除POSIX C語言環境外,它是UTF-8。在其他作業系統上,取決於使用者的區域設定,比如:Windows上,它是基於內碼表的字符集,如Windows-1252或Windows-31j。如果不清楚Java應用執行環境的預設編碼,可以使用這個命令檢視當前JDK的預設字符集:
java -XshowSettings:properties -version 2>&1 | grep file.encoding
程式猿DD Tips:在過去的版本中,當讀寫檔案時,沒有指明字符集的話,所選擇的字符集與作業系統、使用者區域等因素相關,而不同的作業系統的預設編碼不同,所以很可能會出現讀寫編碼不一致的情況,從而導致程式在不同系統下執行出現亂碼問題。所以這一更改可以讓Java開發的應用具備更好的移植性。同時,從這一點的改進,也提醒我們,在讀寫檔案的時候,為了你的應用有更好的可移植性,在涉及讀寫操作的時候,一定要加上編碼引數。這樣即使在Java 18之前的版本,也能擁有更好的可移植性,同時為將來升級Java 21提供更好的相容前提。
本文配套視訊:https://www.bilibili.com/video/BV1YY4y1a7vGopen in new window
如果您學習過程中如遇困難?可以加入我們超高質量的技術交流群,參與交流與討論,更好的學習與進步!另外,不要走開,關注我!持續更新Java新特性教程!
歡迎關注我的公眾號:程式猿DD。第一時間瞭解前沿行業訊息、分享深度技術乾貨、獲取優質學習資源