Текстовые блоки Java
Пишите многострочные строковые литералы в Java с помощью текстовых блоков (тройные кавычки).
Текстовый блок — это многострочный строковый литерал, избавляющий от лишних экранирований символов новой строки и конкатенации. Введённый как предварительная функция в Java 13 и ставший постоянным в Java 15, он позволяет вставлять HTML, JSON, SQL или любой форматированный текст прямо в исходный код — так, чтобы он читался в своём естественном виде.
До появления текстовых блоков несколько строк встроенной разметки превращались в нагромождение экранирований \n и операторов +. Текстовый блок открывается тремя двойными кавычками (""") с последующим переводом строки, и всё вплоть до закрывающего """ становится строкой — с интеллектуальной обработкой ведущих пробелов.
Синтаксис тройных кавычек
Текстовый блок начинается с """ и символа конца строки. Содержимое начинается со следующей строки; открывающий разделитель не может находиться в одной строке с текстом. Блок завершается ещё одним """.
// Old way: escapes and concatenation
String json = "{\n" +
" \"name\": \"Ada\"\n" +
"}";
// Text block: paste it as-is
String block = """
{
"name": "Ada"
}
""";String s = """{. The opening """ must be followed immediately by a line terminator — only the closing """ may share its line with text.Оба варианта дают практически идентичные строки, но текстовый блок читается с первого взгляда, а встроенные двойные кавычки не требуют экранирования. Текстовый блок — это String, как и любой другой, отдельного типа не существует, поэтому все методы String работают с ним, и текстовый блок по-прежнему неизменяем после создания.
Случайные и существенные пробелы
Компилятор разделяет случайные пробелы (отступы, добавленные только для того, чтобы исходный код выглядел аккуратно) и существенные пробелы (отступы, которые вы действительно хотите видеть в значении строки). Он находит строку с наименьшим количеством ведущих пробелов — включая строку с закрывающим """ — и удаляет это общее количество из каждой строки.
String html = """
<p>Hi</p>
""";
// The closing """ is indented 4 spaces, the <p> 8 spaces.
// Common minimum is 4, so the result keeps 4 leading spaces: " <p>Hi</p>\n"Перемещение закрывающего разделителя меняет количество удаляемых символов. Если поместить """ в самом начале строки, отступы не удаляются; если поставить его под самой глубокой строкой — удаляются все. Это даёт точный контроль без ручного подсчёта пробелов.
Экранирование и завершающий перевод строки
Текстовые блоки поддерживают обычные управляющие последовательности, а также две, существующие только для них:
| Экранирование | Эффект |
|---|---|
\n, \t, \" | Стандартные управляющие последовательности, по-прежнему действительны |
\ (в конце строки) | Продолжение строки — подавляет следующий символ новой строки |
\s | Одиночный пробел, который никогда не удаляется как случайный пробел |
Текстовый блок, содержимое которого заканчивается на отдельной строке, включает завершающий символ новой строки; размещение закрывающего """ на той же строке, что и последний текст, исключает его.
String withNewline = """
last line
"""; // ends with "\n"
String noNewline = """
last line"""; // no trailing newlineРаспространённые случаи использования
Текстовые блоки особенно удобны там, где в коде присутствует форматированный многострочный текст:
// SQL kept readable instead of one long escaped string
String query = """
SELECT id, name, price
FROM products
WHERE price < ?
ORDER BY name
""";
// JSON payload with quotes that need no escaping
String payload = """
{
"user": "ada",
"roles": ["admin", "editor"]
}
""";Поскольку текст отражает свою окончательную форму, копирование фрагмента из файла .sql или .json работает сразу, а рецензенты могут немедленно заметить ошибки форматирования.
Текстовые блоки в действии
Пример ниже демонстрирует все возможности: удаление случайных пробелов, formatted() для подстановки значений, поток lines(), экранирования \s и \ в конце строки, управление отступами с помощью разделителя, а также встроенные кавычки без экранирования. Читайте комментарии — каждая строка соответствует одному правилу выше.
Что можно извлечь из результата выполнения:
- Необработанный блок выводит
<html>с левого края, хотя в исходном коде он был с отступом, поскольку общий случайный пробел был удалён относительно закрывающего""". formatted("World")подставляет заполнитель%s, доказывая, что текстовый блок — это обычнаяString, которую можно передавать методам форматирования.Line count: 5получается изhtml.lines(), перебирающего пять строк содержимого; завершающий символ новой строки, добавляемый закрывающим"""на отдельной строке, завершает последнюю строку, а не создаёт пустую шестую.Has trailing space: trueпоказывает, что\sпринудил пробел сохраниться там, где компилятор иначе удалил бы его как случайный.Continuation: Roses are red, violets are blue.доказывает, что\в конце строки объединил две строки источника в одну, а{"name": "Ada", "active": true}выведен без единой экранированной кавычки.