Перейти к основному содержимому

Текстовые блоки Java

· 5 мин. чтения

1. Введение

В предыдущем уроке мы видели, как можно использовать многострочные строки в любой версии Java.

В этом руководстве мы подробно рассмотрим, как использовать функцию текстовых блоков Java 15 для наиболее эффективного объявления многострочных строк.

2. Использование

Начиная с Java 15 текстовые блоки доступны в качестве стандартной функции. В Java 13 и 14 нам нужно было включить ее в качестве функции предварительного просмотра .

Текстовые блоки начинаются с «» (три двойных кавычки), за которыми следуют необязательные пробелы и новая строка. Самый простой пример выглядит так:

String example = """
Example text""";

Обратите внимание, что тип результата текстового блока по-прежнему String . Текстовые блоки просто предоставляют нам еще один способ записи строковых литералов в нашем исходном коде.

Внутри текстовых блоков мы можем свободно использовать новые строки и кавычки без необходимости экранирования разрывов строк . Это позволяет нам включать буквальные фрагменты HTML, JSON, SQL или чего-то еще, что нам нужно, более элегантным и удобочитаемым способом.

В результирующую строку не включаются (базовый) отступ и первая новая строка. Мы рассмотрим передачу отступов в следующем разделе.

3. Отступ

К счастью, при использовании текстовых блоков мы по-прежнему можем делать правильный отступ в коде . Для этого часть отступа рассматривается как исходный код, а другая часть отступа рассматривается как часть текстового блока. Чтобы это работало, компилятор проверяет минимальный отступ во всех непустых строках. Затем компилятор сдвигает весь текстовый блок влево.

Рассмотрим текстовый блок, содержащий некоторый HTML:

public String getBlockOfHtml() {
return """
<html>

<body>
<span>example text</span>
</body>
</html>""";
}

В этом случае минимальный отступ составляет 12 пробелов. Таким образом удаляются все 12 пробелов слева от <html> и во всех последующих строках. Давайте проверим это:

@Test
void givenAnOldStyleMultilineString_whenComparing_thenEqualsTextBlock() {
String expected = "<html>\n"
+ "\n"
+ " <body>\n"
+ " <span>example text</span>\n"
+ " </body>\n"
+ "</html>";
assertThat(subject.getBlockOfHtml()).isEqualTo(expected);
}

@Test
void givenAnOldStyleString_whenComparing_thenEqualsTextBlock() {
String expected = "<html>\n\n <body>\n <span>example text</span>\n </body>\n</html>";
assertThat(subject.getBlockOfHtml())
.isEqualTo(expected);
}

Когда нам нужен явный отступ , мы можем использовать меньший отступ для непустой строки (или последней строки):

public String getNonStandardIndent() {
return """
Indent
""";
}

@Test
void givenAnIndentedString_thenMatchesIndentedOldStyle() {
assertThat(subject.getNonStandardIndent())
.isEqualTo(" Indent\n");
}

Более того, мы также можем использовать экранирование внутри текстовых блоков, как мы увидим в следующем разделе.

4. Побег

4.1. Экранирование двойных кавычек

Внутри текстовых блоков двойные кавычки не нужно экранировать. Мы могли бы даже снова использовать три двойных кавычки в нашем текстовом блоке, экранировав одну из них:

public String getTextWithEscapes() {
return """
"fun" with
whitespace
and other escapes \"""
""";
}

Это единственный случай, когда необходимо экранировать двойные кавычки. В остальных случаях это считается плохой практикой.

4.2. Экранирование терминаторов строки

Как правило, символы новой строки не нужно экранировать внутри текстовых блоков.

Однако обратите внимание, что даже если исходный файл имеет окончания строк Windows ( \r\n ), текстовые блоки будут заканчиваться только символами новой строки ( \n ) . Если нам нужно, чтобы символы возврата каретки ( \r ) присутствовали, мы должны явно добавить их в текстовый блок:

public String getTextWithCarriageReturns() {
return """
separated with\r
carriage returns""";
}

@Test
void givenATextWithCarriageReturns_thenItContainsBoth() {
assertThat(subject.getTextWithCarriageReturns())
.isEqualTo("separated with\r\ncarriage returns");
}

Иногда в нашем исходном коде могут быть длинные строки текста, которые мы хотим отформатировать в удобочитаемом виде. Предварительный просмотр Java 14 добавил функцию, которая позволяет нам это делать. Мы можем экранировать новую строку, чтобы она игнорировалась :

public String getIgnoredNewLines() {
return """
This is a long test which looks to \
have a newline but actually does not""";
}

На самом деле этот литерал String будет просто равен обычной непрерываемой String :

@Test
void givenAStringWithEscapedNewLines_thenTheResultHasNoNewLines() {
String expected = "This is a long test which looks to have a newline but actually does not";
assertThat(subject.getIgnoredNewLines())
.isEqualTo(expected);
}

4.3. Экранирование пробелов

Компилятор игнорирует все конечные пробелы в текстовых блоках . Однако, начиная с предварительной версии Java 14, мы можем избежать пробела, используя новую управляющую последовательность \s . Компилятор также сохранит все пробелы перед этим пробелом.

Давайте подробнее рассмотрим влияние сбежавшего пробела:

public String getEscapedSpaces() {
return """
line 1·······
line 2·······\s
""";
}

@Test
void givenAStringWithEscapesSpaces_thenTheResultHasLinesEndingWithSpaces() {
String expected = "line 1\nline 2 \n";
assertThat(subject.getEscapedSpaces())
.isEqualTo(expected);
}

Примечание : пробелы в приведенном выше примере заменены символом '·', чтобы сделать их видимыми.

Компилятор удалит пробелы из первой строки. Однако вторая строка завершается экранированным пробелом, и, таким образом, все пробелы сохраняются.

5. Форматирование

Чтобы облегчить подстановку переменных, был добавлен новый метод, который позволяет вызывать метод String.format непосредственно для литерала String:

public String getFormattedText(String parameter) {
return """
Some parameter: %s
""".formatted(parameter);
}

6. Заключение

В этом кратком руководстве мы рассмотрели функцию текстовых блоков Java. Возможно, это не изменит правила игры, но поможет нам писать более качественный и читаемый код, что в целом хорошо.

Как всегда, полный исходный код статьи доступен на GitHub .