在Java 18中,將UTF-8指定為標準Java API的預設字元集。有了這一更改,依賴於預設字元集的API將在所有實現、操作系統、區域設置和配置中保持一致。 做這一更改的主要目標: 當Java程式的代碼依賴於預設字元集時,使其更具可預測性和可移植性。 闡明標準Java API在哪裡使用預設字元集 ...
在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。第一時間瞭解前沿行業消息、分享深度技術乾貨、獲取優質學習資源