好用!期待已久的文本塊功能究竟如何在 Java 13 中發揮做用?

本文由 yanglbme 原創,首發於公衆號「Doocs開源社區」,禁止未受權轉載。html

「你繼續半年一更,我繼續用 Java 7/8」。java

這多是不少朋友目前的真實狀況。說實話,Java 「每半年發佈一個新版本」的節奏確實快了點。但無論怎樣,新技術、新特性仍是值得咱們學一學。git

在 Java 13 中,有了文本塊,咱們能夠輕鬆地使用多行字符串。咱們再也不須要對字符串中的特殊字符進行轉義,也沒必要對跨越多行的字符串使用 + 串聯運算符,它極大地提升代碼的可讀性。在這篇文章中,我將介紹關於 Java 13 文本塊的功能以及使用場景,一塊兒來看看吧。github

什麼是文本塊?

String 數據類型多是 Java 開發人員最經常使用的類型之一。它能夠以任何語言存儲從幾個字符到多行的全部內容。不過,這種靈活性也致使某些 String 值難以閱讀或修改。例如,那些帶有引號,轉義字符或跨越多行的字符串。web

文本塊是 Java 13 的一項預覽功能,咱們可使用文本塊輕鬆定義多行字符串而無須添加串聯運算符和轉義字符。此外,咱們還能夠控制如何格式化字符串值。正則表達式

讓咱們看看如下 HTML 代碼段:json

String html = """
<HTML>
  <BODY>
    <H1>"Java 13 is here!"</H1>
  </BODY>
</HTML>""";
複製代碼

注意,三個雙引號 """ 分別定義了塊的開始和結尾。看一下在 Java 13 之前是如何定義的:bash

String html = 
  "<HTML>\n\t<BODY>\n\t\t<H1>\"Java 13 is here!\"</H1> \n\t</BODY>\n</HTML>\n";
複製代碼

或者,更加典型的是:app

String html = "<HTML>" +
"\n\t" + "<BODY>" +
"\n\t\t" + "<H1>\"Java 13 is here!\"</H1>" +
"\n\t" + "</BODY>" +
"\n" + "</HTML>";
複製代碼

上面的這兩種寫法,在可讀性上遠遠不如不如文本塊。編碼

文本塊語法

就像前面提到的,Java 13 使用三個雙引號 """ 做爲開始和結束定界符來定義文本塊。開始定界符後面能夠跟零個或者多個空格一個行終止符結束符沒有相似的規則

這樣的語法規則,致使如下示例實際上是無效的文本塊由於它們在開頭定界符以後並無包含一個行終止符

String multilineValue1 = """ """;
String multilineValue2 = """""";
複製代碼

這只是預覽特性

文本塊在 Java 13 中做爲預覽特性發布,但預覽特性並不意味着它是不完整或半生不熟的功能。從本質上講,這意味着即便開發人員可使用此功能,它也可能在未來的 Java 版本中更改。

這實際上是有緣由的。經過「每六個月發佈一個新版本」的節奏,開發人員能夠很快使用到新的語言功能。可是,在向 Java 永久添加語言功能以前,Java 團隊會評估開發人員對此的評價。根據反饋的不一樣,能夠在將預覽功能添加到 Java SE 以前對其進行完善,也能夠將其徹底刪除。

要體驗預覽語言功能,咱們須要使用編譯和運行時手動啓用它們。這樣能夠確保咱們不會意外使用預覽功能。要使用文本塊編譯源文件,請使用 --enable-preview-release 13 選項。如下示例演示瞭如何使用命令行來編譯源文件,例如對於 Java13.java 文件:

javac --enable-preview --release 13 Java13.java
複製代碼

爲了增強預覽功能可能會發生的變化,當咱們執行前面的命令時,將會獲得以下所示的編譯器警告。

Note: Java13.java uses preview language features.
Note: Recompile with Xlint:preview for details.
複製代碼

要執行類 Java13,咱們須要使用 --enable-preview 選項:

java --enable-preview Java13
複製代碼

接下來,咱們來看一下文本塊的實現。

依然是字符串數據類型

傳統的字符串和文本塊都被編譯爲相同的類型:String。字節碼類文件沒法區分字符串值是從傳統字符串仍是文本塊派生而來。這意味着文本塊值存儲在字符串池中。

考慮如下代碼,你以爲變量 traditonalStringtextBlockString 引用相同的 String 實例嗎?

String traditionalString = "Java";
String textBlockString = """
Java""";
System.out.println(traditionalString == textBlockString);
複製代碼

答案是確定的,由於它們的內容是徹底相同的,因此上面的代碼將會輸出 true

在文章的開頭,我討論了使用傳統的 String 處理多行字符串的繁瑣,接下來,咱們就來看看文本塊在 Java 13 中如何提供便利?

輕鬆處理多行值

定義 JSON

開發人員常用多行字符串值,例如 JSON,HTML,XML 或正則表達式(regex)數據。經過文本塊,使用多行 JSON 值的方法變得很簡單。

String json = """
    {
      "name": "web",
      "version": "1.0.0",
      "dependencies": "AppA"
    }
""";
複製代碼

沒有了轉義字符和鏈接運算符,代碼在視覺上顯得很直觀,所以,咱們能夠輕鬆編輯修改 JSON 值。不信?對比一下使用傳統的 String 來定義 JSON 值:

String json = 
    "{" +
      "\"name\": \"web\"," +
      "\"version\": \"1.0.0\"," +
      "\"dependencies\": \"AppA\" + 
    "}";
複製代碼

定義 SQL

有時候,咱們須要將 SQL 查詢語句存儲爲字符串。假如咱們使用 String 變量存儲了一個多行 SQL 查詢語句,以下所示(對於 Java 12 或更早版本):

String query = 
  "SELECT name, age" +
  "FROM EMP" + 
  "WHERE name = \'John\' +
  "AND age > 20";
複製代碼

是否是以爲好像沒毛病?實際上是有問題的,它是一個無效的 SQL 查詢語句。因爲每行末尾都少了空格,這個查詢語句會被解釋爲如下內容:

SELECT name, ageFROM EMPWHERE name = 'John'AND age > 20
複製代碼

要是使用文本塊,就能夠避免出現相似問題:

String query = """
  SELECT name, age
  FROM EMP
  WHERE name = 'John'
    AND age > 20
  """;
複製代碼

定義正則表達式

正則表達式一般會包含許多特殊字符。在 Java 13 以前,咱們將一個正則表達式寫爲 String 時,經常須要轉義一些特殊字符,這使得咱們難以編寫、閱讀或理解這些表達式。

這是一個在文本塊以前存儲正則表達式 [0-9]{3}\-[0-9]{4} 的示例:

String java12OrBeforeRegex = "[0-9]{3}\\t-[0-9]{4}";
複製代碼

有了文本塊,咱們能夠定義出相同的正則表達式,以下所示:

String java13Regex = """
[0-9]{3}\t-[0-9]{4}""";
複製代碼

文本塊中的轉義字符

咱們能夠將各類轉義字符添加到文本塊,就像將它們添加到 String 中同樣。例如,能夠經過將值放在多行上或使用轉義字符(例如 \n)來在文本塊中包含換行符。在如下代碼中,I'mhappy 將會分別在兩個行上。

String html = """
<HTML>
  <BODY>
    <H1>I'm \nhappy</H1>
  </BODY>
</HTML>""";
複製代碼

空格與縮進如何處理?

一個關鍵問題是如何處理文本塊中附帶的空白符。事實上,它由編譯器很好地處理。在文本塊中,任何行上最左邊的非空白字符最左邊的分隔符定義了字符串開始的位置。

在下圖中,咱們能夠看到 getHTML() 方法返回了一個 String 類型的值,String 值的最左非空白字符以 < (<HTML>中的<)開頭,該字符與結束定界符對齊

上面圖中的這段代碼,其實返回了下圖所示的字符串(第一行<HTML>和最後一行</HTML>都不包含任何前導空格):

若要將字符串開頭的空白字符標記爲必需的(即:保留<HTML>左側的空白符),咱們須要向左移動分隔符或者任何非空白字符。

好比,咱們將閉合定界符 """ 向左移動 8 個空格:

修改後的代碼將會返回下圖所示的 String 值,能夠看到每行都添加了 8 個前導空格,外加用戶額外縮進的空格。

默認狀況下,文本塊會刪除每行末尾的空格。若是須要添加它們,可使用八進制轉義字符 \040(在 ASCII 中,空格爲 32)來強制包含它們。

如下是一個示例,該示例在文本塊第二行的末尾添加了一個空格:

String campaign = """
            Don't leave home without -
            money &\040
            carry bag.
            Reduce | Reuse
            """;
複製代碼

注意,若是基本空格包含製表符 \t,則不會將其擴展,而是算做單個空格。

串聯文本塊

文本塊能夠與傳統的字符串值經過 + 鏈接,如下是一個例子:

String concatenate() {
    return """
            Items to avoid -
            Single
            Use
            Plastics
            """ 
            + 
            "Let's pledge to find alternatives";
}
複製代碼

之因此提供這種方式,是由於咱們有時候須要在字符串中插入變量的值:

String concatenate(Object obj) {
    return """
            Items to avoid -
            Single
            Use
            """
            + obj + """
            Let's pledge to find 
            alternatives""";
}
複製代碼

文本塊能夠看成字符串來使用,好處就是咱們能夠在文本塊中使用 String 的方法。例如,咱們可使用 String.replace() 方法而無需作任何特殊處理:

String concatenateReplace(Object obj) {
    return """
        Items to avoid -
        Single
        Use
        $type
        Let's pledge to find
        alternatives""".replace("$type", obj.toString());
}
複製代碼

一樣,咱們可使用 format() 方法或者 String 的任何其餘方法。

總結

關於 Java 13 文本塊的說明,這篇文章已經足夠詳細。文本塊能夠幫助咱們開發人員輕鬆處理多行字符串值。須要記住,文本塊目前只是一個預覽功能,它隨時可能更改。但即便以當前文本塊的這種能力,它也一定會爲咱們節省不少的編碼工做。

相關文章
相關標籤/搜索