Существует понятие случайное пробел .
Обработка во время компиляции
Текстовый блок является константным выражением типа String, как строковый литерал.Однако, в отличие от строкового литерала, содержимое текстового блока обрабатывается компилятором Java в три этапа:
Ограничители строки в содержимом переводятся в LF (\ u000A).Цель этого перевода - следовать принципу наименьшего удивления при перемещении исходного кода Java по платформам.
Случайное пустое пространство вокруг содержимого, введенное для соответствия отступу Javaисходный код удален.
Последовательности Escape в содержимом интерпретируются.Выполнение интерпретации в качестве последнего шага означает, что разработчики могут писать escape-последовательности, такие как \ n, без их изменения или удаления на более ранних этапах.
...
Случайный пробел
Вот пример HTML с использованием точек для визуализации пробелов, добавленных разработчиком для отступа:
String html = """
..............<html>
.............. <body>
.............. <p>Hello, world</p>
.............. </body>
..............</html>
..............""";
Поскольку открывающий разделитель обычно расположен для отображения ната же строка, что и оператор или выражение, которое использует текстовый блок, не имеет никакого реального значения для того факта, что 14 визуализированных пробелов начинаются с каждой строки.Включение этих пробелов в содержимое означало бы, что текстовый блок обозначает строку, отличную от строки, обозначенной конкатенированными строковыми литералами.Это повредит миграции и станет источником неожиданности: в подавляющем большинстве случаев разработчик не хочет, чтобы эти пробелы в строке.Кроме того, закрывающий разделитель обычно располагается так, чтобы выровняться с содержимым, что дополнительно предполагает, что 14 визуализируемых пробелов незначительны.
...
Соответственно, подходящей интерпретацией для содержимого текстового блока являетсячтобы отделить случайный пробел в начале и конце каждой строки от необходимого пробела. Компилятор Java обрабатывает содержимое, удаляя случайный пробел, чтобы получить то, что разработчик намеревался.
Вашдопущение, что
Hello,
Java 13
<empty line>
равно
....Hello,
....Java 13
<empty line>
является неточным, поскольку это существенно пробелы и они не будут удалены никомпилятор или String#stripIndent
.
Чтобы прояснить ситуацию, давайте продолжим представлять случайный пробел в виде точки.
String hello = """
....Hello,
....Java 13
....""";
String hello2 = """
Hello,
Java 13
""";
Давайте напечатаем их.
Hello,
Java 13
<empty line>
Hello,
Java 13
<empty line>
Давайте назовем String#stripIndent
на обоих и распечатаем результаты.
Hello,
Java 13
<empty line>
Hello,
Java 13
<empty line>
Чтобы понять, почему ничего не изменилось, нам нужно разобраться в этом.электронная документация.
Возвращает строку, значением которой является эта строка, с случайным пробелом , удаленным из начала и концакаждая строка.
Тогда минимальный отступ (мин) определяется следующим образом.Для каждой непустой строки (как определено isBlank()
) подсчитываются начальные пробельные символы. Первые пробельные символы в последней строке также учитываются, даже если они пустые. Минимальное значение является наименьшим из этих значений.
Для каждой непустой строки минимальные первые пробельные символыудаляются, а любые завершающие пробелы удаляются.Пустые строки заменяются пустой строкой.
Для обоих String
с минимальным отступом является 0
.
Hello, // 0
Java 13 // 0 min(0, 0, 0) = 0
<empty line> // 0
Hello, // 4
Java 13 // 4 min(4, 4, 0) = 0
<empty line> // 0
String#stripIndent
предоставляет разработчикам доступ к Java-версии алгоритма повторного отступа, используемого компилятором.
Алгоритм повторного отступа будет нормативнымв спецификации языка Java.Разработчики будут иметь к нему доступ через String::stripIndent
, новый метод экземпляра.
Строка, представленная текстовым блоком, не является буквальной последовательностью символов в содержимом.Вместо этого строка, представленная текстовым блоком, является результатом применения следующих преобразований к содержимому в следующем порядке:
Ограничители строки нормализуются к символу ASCII LF (...)
Удален случайный пробел, , как будто при выполнении String::stripIndent
для символов в содержимом.
Escape-последовательности интерпретируются, как в строковом литерале.