Java 13 наконец-то обеспечивает поддержку многострочных строковых литералов после отказа от аналогичной функциональности из Java 12.
Строковые литералы в Java
Объявить строковый литерал в Java несложно:
String myString = "Behold, a string literal!";
Ничего нового, верно? Однако традиционные строковые литералы имеют некоторые неудобные ограничения.
Прежде всего, весь литерал должен находиться всего в одной строке. Это нормально для простых коротких строк, но для более длинных вам нужно прибегнуть к объединению нескольких строковых литералов. Если вы хотите также включить разрывы строк, вам нужно добавить \n
.
String myString = "This is my string\n" + "which I want to be \n" + "on multiple lines.";
Это громоздко и трудно читаемо. Другая проблема заключается в том, что различные символы не могут быть представлены напрямую, но их необходимо экранировать, например "
или \
. Это делает ваши строки еще более трудными для чтения и работы с ними.
String path = "Open \"C:\\Program Files\\Java\\jdk1.8.0_152\"";
Это становится особенно запутанным в таких случаях, как регулярные выражения. Однако как справиться с этой проблемой?
Другие языки JVM
Как обычно, Java опаздывает с внедрением функциональности, которая уже распространена во многих других языках, даже на JVM. Kotlin, Scala или Groovy уже поддерживают многострочные строковые литералы, использующие """
обозначения вместо обычных "
. Посмотрите на следующий пример в Kotlin.
val text = """ This is my cool string, which I want to span multiple lines. It can have backslash \ and even double-quotes " """
Как вы можете заметить, он не только многострочный, но и вам больше не нужно экранировать свои символы. Это называется необработанным строковым литералом, что означает, что все символы интерпретируются как есть и экранирование не требуется.
Необработанные строковые литералы в Java
В Java 12 изначально предлагалось включить Необработанные строковые литералы (JEP-326) . Поведение было очень похоже на приведенный выше пример в Kotlin. Но вместо использования """"
, как в других языках JVM, в нем использовалась обратная нотация. Концепция была немного необычной в том смысле, что вы могли использовать любое количество обратных ссылок и такое же количество обратных ссылок в конце. Таким образом, не было необходимости экранировать обратные метки внутри литерала spring, независимо от того, сколько последовательных обратных меток присутствовало.
Одной из проблем с необработанными строковыми литералами обычно является отступ. Каждый символ в многострочном необработанном строковом литерале интерпретируется как есть, включая отступ, который должен быть там только для лучшей читаемости кода, а не как часть самого литерала. Рассмотрим следующий пример:
public static void main(String[] args) { String myString = `This is my string which I want to be on multiple lines.`; System.out.println(myString); }
Если вы распечатаете его, то во всех строках, кроме первой, будут присутствовать отступы.
This is my string which I want to be on multiple lines.
Вам нужно будет исправить это вручную, возможно, с помощью недавно предложенных строковых методов align()
и отступ()
. Не очень практично, но это то, с чем вам пришлось бы смириться, если бы вы использовали необработанные строки.
Вы можете прочитать больше об исходном предложении необработанных строковых литералов в следующей статье :
Однако это предложение было отклонено до окончательного выпуска Java 12 и в настоящее время считается устаревшим.
В то время как мы можем ожидать, что для любой языковой функции будет нетривиальный объем отзывов “Я бы предпочел это по-другому”, анализируя отзывы, которые мы получили, я больше не уверен, что мы все еще достигли правильного набора компромиссов между сложностью и выразительностью, или что мы достигли изучили достаточно дизайнерского пространства, чтобы быть уверенными, что текущий дизайн – это лучшее, что мы можем сделать. Отказавшись, мы можем продолжить доработку дизайна, изучить дополнительные варианты и стремиться к предварительному просмотру, который действительно соответствует требованиям процесса предварительного просмотра функций (JEP 12).
Многострочные строковые литералы в Java
После отзыва первоначального предложения обсуждение было возобновлено и привело к совершенно новому предложению, которое будет представлено в Java 13 в качестве функции предварительного просмотра. Он называется JEP 355: Текстовые блоки (предварительный просмотр) .
Предполагается, что это не реализация необработанных строковых литералов, а скорее многострочные строковые литералы, которые по-прежнему будут допускать экранирование, хотя вам не потребуется использовать их все. Кроме того, не будет необходимости обрабатывать все проблемы с отступами, что было необходимо для необработанных строковых литералов.
Функция предварительного просмотра
Текстовые блоки будут доступны только в качестве функции предварительного просмотра в Java 13. Что это значит?
Язык предварительного просмотра или функция виртуальной машины – это новая функция платформы Java SE, которая полностью определена, полностью реализована и в то же время непостоянна. Он доступен в выпуске функций JDK, чтобы вызвать обратную связь разработчиков, основанную на реальном использовании; это может привести к тому, что он станет постоянным в будущей платформе Java SE.
Перед следующим выпуском функций JDK будут оценены сильные и слабые стороны функций “реального мира”, чтобы решить, играет ли функция долгосрочную роль в платформе Java SE, и если да, то нуждается ли она в доработке. Следовательно, функции может быть присвоен окончательный и постоянный статус (с уточнениями или без них), или пройти дополнительный период предварительного просмотра (с уточнениями или без них), или же быть удалена.
Такие функции поставляются в JDK, но по умолчанию не включены. Вам нужно явно разрешить им использовать их. Излишне говорить, что он предназначен не для производственного использования, а скорее для оценки и экспериментов, поскольку он может быть удален или сильно изменен в будущем выпуске.
Вам нужно будет загрузить JDK 13 . В IntelliJ перейдите в File = Project Structure
и убедитесь, что у вас выбран JDK13 в разделе Project SDK. Чтобы включить текстовые блоки в качестве функции предварительного просмотра, обязательно выберите 13 (Предварительный просмотр) - Текстовые блоки
в разделе Уровень языка проекта
.
При создании приложения вручную вам необходимо указать, что функции предварительного просмотра должны быть включены, указав следующие параметры в javac
:
javac --release 13 --enable-preview ...
Это для времени компиляции. Во время выполнения вы просто предоставляете --enable-preview
java --enable-preview ...
Текстовые блоки
В отличие от отклоненных необработанных строковых литералов, текстовые блоки заключены в три двойные кавычки """"
, такие же, как в Groovy или Kotlin. Это больше согласуется с обычными строковыми литералами и другими языками JVM.
String myBlock = """ line 1 line 2 line 3 """
Нет никакой разницы во время выполнения между текстовым блоком и строковым литералом. Оба результата приводят к экземпляру String. Если они имеют одинаковое значение, они будут интернированы, как обычно, и в конечном итоге станут одним и тем же экземпляром. Везде, где вы можете использовать строковый литерал, вы также можете использовать текстовый блок.
Обработка
В отличие от обычных строковых литералов, текстовые блоки обрабатываются компилятором в три этапа:
- Концы линии нормализуются
- Лишние пробелы удаляются
- Экранированные символы интерпретируются
Нормализация конца строки
Операционные системы на базе Windows и UNIX имеют разные символы для обозначения окончаний строк.
Windows использует возврат каретки \r
и Перевод строки \n
, в то время как системы на базе Unix используют только перевод строки. Проблема в том, что текстовые блоки используют символы новой строки непосредственно из исходного кода, вместо использования \n
, таких как обычные строковые литералы. Это означает, что исходный код, созданный в Unix, будет содержать строки с разными окончаниями строк при компиляции в Windows. Строки выглядели бы идентично невооруженным глазом, но имели бы разные окончания строк.
Чтобы предотвратить это, компилятор Java принимает все окончания строк в текстовых блоках и нормализует их до перевода строки \n
. Важно то, что это делается перед вычислением экранированных символов. Это означает, что если вам явно необходимо включить возврат каретки с помощью \r
, вы можете это сделать, поскольку он вычисляется после нормализации окончания строки и не будет затронут.
Удаление вмятин
Помните пример с необработанными строковыми литералами и отступами? Необработанные строковые литералы интерпретируют все символы, включая отступы. Таким образом, пробелы, которые должны были просто облегчить чтение вашего исходного кода, на самом деле становятся частью ваших строк. В подавляющем большинстве случаев это нежелательное поведение.
К счастью, компилятор Java удаляет нежелательные пробелы при компиляции текстовых блоков.
- Все конечные пробелы удаляются из конца строк.
- Начальный общий пробел удаляется из начала каждой строки.
Что именно это означает? Давайте посмотрим на следующий код:
public static void main(String[] args) { String html = """Hello, world
"""; }
Фрагмент HTML-кода содержит много пробелов, но на самом деле он ему не принадлежит. Это просто делает его хорошо выровненным в исходном файле. Что важно, так это относительный отступ внутри блока.
Другими словами: если каждая строка в фрагменте начинается с 22 пробелов, мы можем их игнорировать. Эти 22 пробела представляют собой общий префикс пробела , который можно игнорировать, и следует сохранить только то, что находится поверх него.
Давайте заменим общий префикс на .
. Все эти пробелы будут отброшены. Будут сохранены только пробелы, отмеченные символом -
, поскольку они превышают общий префикс пробела.
String html = """ .............. ..............-- ..............----Text Blocks are awesome!
..............-- .............. ..............""";
Результатом будет:
Text Blocks are awesome!
Обратите внимание, что на этом шаге удаляются только прямые пробелы. Если у вас есть пробелы в виде экранированных символов, таких как \n
или \t
, они не будут удалены.
Спасаясь
Текстовые блоки не являются необработанными строками, и вы все равно можете использовать экранирование. Однако вам не нужно беспокоиться о самых распространенных из них.
- Новая строка
\n
больше не нужна, поскольку текстовые блоки по своей природе многострочны. - Вам не нужно экранировать
"
двойные кавычки, поскольку они больше не отмечают окончание строкового литерала
String myBlock = """ First line Second Line with " quotes """
Поскольку цитирование разрешено, технически вы можете включить \n
и \"
, но это не обязательно и не рекомендуется. Вам все равно нужно избегать косой черты \\
. Но в целом текстовые блоки требуют гораздо меньшего экранирования, чем старые добрые строковые литералы. Все escape-последовательности, которые могут быть использованы в строковых литералах, также могут быть использованы для текстовых блоков. Проверьте Java spec для получения полного списка.
Интерпретация экранированных символов как последнего из трех шагов важна, поскольку нормализация окончания строки и удаление пробелов не влияют на ваши экранированные символы.
Новые Строковые методы
В рамках предложения по текстовым блокам появились три новых метода класса String
.
translate Escapes()
– преобразует escape-последовательности в строке, за исключением символов unicode.strip Indent()
– удаляет общие пробелы из начала каждой строки.отформатированный(Объект... аргументы)
– Удобный метод, эквивалент String.format(строка, аргументы)
Вывод
- Текстовые блоки предлагают удобный способ работы с многострочными строковыми литералами.
- Чтобы создать текстовый блок, просто окружите свою строку символом
""""
. - Вы можете использовать текстовые блоки в любом месте, где вы можете использовать строковые литералы
- Окончания строк нормализуются до НЧ
- Лишние пробелы удаляются с начала и конца каждой строки. Сохраняется только относительный отступ.
- Это функция предварительного просмотра в Java 13, которая должна быть явно включена
- Предложение о необработанных строковых литералах было изъято из Java 12; вместо этого позже были введены текстовые блоки
Оригинал: “https://dev.to/vojtechruz/java-13-text-blocks-6nb”