Рубрики
Без рубрики

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

В Java написание многострочных строк не доставляет удовольствия, вы должны написать код, в котором требуется p… Помеченный как java, производительность.

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

Смотрите приведенный ниже пример, где мы пытаемся поместить JSON в виде строки

String sampleJson = "{\"name\":\"josh\",\"salary\":\"8000$\",\"age\":27,\"isMarried\":\"True\"}";

здесь у нас есть очень простой JSON с большим количеством escape-последовательностей, его очень трудно прочитать.

мы можем сделать лучше, чтобы сделать его читабельным, см. Ниже

String sampleJsonReadableABit = "{" +
        "\"name\":\"josh\"," +
        "\"salary\":\"8000$\"," +
        "\"age\":27," +
        "\"isMarried\":\"True\""+
        "}";

Это лучше, чем раньше, но все еще трудно читается (много конкатенаций и escape-последовательностей) и подвержено ошибкам. Добавление или удаление другого атрибута непросто для любого разработчика.

Основная цель введения текстовых блоков состоит в том, чтобы

  • Простота написания многострочных строк
  • Удалите escape-последовательность и улучшите удобочитаемость
  • Разумно обрабатывайте пробелы и отступы

Что такое Текстовые блоки?

Текстовые блоки были выпущены в качестве функции предварительного просмотра с JDK13 в июне 2019 года на основе отзывов, которые снова просматриваются как JEP 368 с JDK 14.

Эта функция долгое время отсутствовала у разработчика, особенно когда кому-то приходится читать такой код, в который встроен документ JSON или инструкции SQL.

Как определение ” ** Текстовый блок представляет собой многострочный строковый литерал, который позволяет избежать необходимости в большинстве escape-последовательностей, автоматически форматирует строку предсказуемым образом и дает разработчику контроль над форматом, когда это необходимо* *”.

Текстовый блок определяется тремя двойными кавычками “”” |/в качестве открывающего и закрывающего разделителя.

Давайте посмотрим, как приведенный выше JSON будет представлен с помощью текстовых блоков

String jsonAsTextBlocks =  """
        {
        "name":"josh",
        "salary":"8000$",
        "age":27,
        "isMarried":"True"
        }
         """;

не лучше ли почитать? Никаких escape-последовательностей:)

Эта функция доступна с такими языками, как Kotlin, Scala или Groovy.

Важные Моменты

  • Открывающий разделитель, должен сопровождаться разделителем строки перед фактическим запуском содержимого, попытка записать текстовые блоки, подобные приведенным ниже, приведет к ошибке во время компиляции.
String textBlockSample = """Ashish //Compile time error
        """;
String textBlockSampleTwo = """Ashish"""; //Compile time error
String textBlockSampleThree = """"""; //Compile time error
String textBlockSampleFour = """ """; //Compile time error

!! В первом примере содержимое размещено сразу после открытия разделителя “”” без разделителя строки. Это недопустимо и приведет к ошибке во время компиляции.

!! Во втором примере также содержимое помещается непосредственно между открывающим “”” и закрывающим разделителем “”” без ограничителя строки (обычно со строкой мы пишем что-то вроде **Строка* *). Это также недопустимо и приведет к ошибке во время компиляции.

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

  • Закрывающий разделитель , таких правил нет. давайте посмотрим несколько образцов
String textBlockSample = """ //valid syntax
        Ashish""";
String textBlockSampleTwo = """ //valid syntax
        Ashish
        """;
String textBlockSampleThree = """ //valid syntax (empty)
        """;
  • Случайное пустое пространство , Текстовый блок отличает четкое различие между случайным пробелом и существенным пробелом. Компилятор Java автоматически удаляет случайные пробелы
  String htmlAsTextBlocks = """
          
             
                  

Sample Heading

""";

Если вы запустите приведенный выше фрагмент кода, вывод будет выглядеть примерно так, как показано ниже,

  
  ...
  ........

........Sample Heading ........

...

любой пробел перед тегом будет рассматриваться как второстепенный пробел и просто удален компилятором, но пробелы, отмеченные символом **…* *, не являются второстепенными, такие пробелы будут рассматриваться как ожидаемые/желаемые/существенные пробелы и соблюдаться компилятором.

Если вы хотите явно добавить некоторое пространство перед содержимым, им можно управлять с помощью закрывающего разделителя ” “” обратите внимание на фрагмент ниже, здесь закрывающий разделитель явно перемещен влево

  String htmlAsTextBlocksWithSpace = """
            
                
                    

Sample Heading

""";

он будет иметь вывод, как показано ниже:

                    
                
                    

Sample Heading

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

  String htmlAsTextBlocksWithSpace = """
          
              
                  

Sample Heading

""";

он будет иметь вывод, подобный

  
     
         

Sample Heading

Чтобы специально добавить немного завершающего пробела, вы можете написать что-то вроде:

  String textBlockWithTrailingSpace = """
          Ashish    \040""";

приведенная выше длина текстового блока, если вы рассчитаете, будет равна 11.

Сходства между текстовыми блоками и строкой

  • В основном мы можем использовать текстовые блоки везде, где применимо использование строк например, если какое-либо определение метода может принимать строковую переменную в качестве аргумента, мы можем передать туда текстовый блок.
private static void textBlocksAsString(String str){
    System.out.println(str);
}

приведенный выше метод может быть вызван как ” ** текстовые блоки в виде строки(“”” I am Fun “””); * *”

Это совершенно корректный синтаксис.

  • Традиционные строковые значения и текстовые блоки компилируются в один и тот же тип: String. Файл класса байт-кода не различает, является ли строковое значение производным от традиционной строки или текстового блока. Это означает, что значения текстовых блоков хранятся в пуле строк как любая обычная строка. Оба равенства вернут значение true если они ссылаются на одно и то же значение. Смотрите приведенный ниже фрагмент кода
String str = "Ashish";
String textBlock = """
        Ashish""";  

​ если у вас что-то есть

System.out.println(str==textBlock);
System.out.println(str.equals(textBlock));

​ Оба оператора выведут true но если вы немного измените приведенный выше код на:

String str = "Ashish";
String textBlock = """
        Ashish
        """;    

оба равенства вернут значение false.

  • Вы можете объединить строковые и текстовые блоки так же, как вы объединяете две строки, см. Ниже
System.out.println( """
    Works
    is fun
    """
        +
        "Let's have some");

Это действительно так.

  • Для определенных бизнес-требований мы должны написать код, в котором строку нужно разделить на основе определенного регулярного выражения и преобразовать в список. Такие варианты использования также были упрощены с помощью текстовых блоков
String fruits = "Apple,Orange,Mango";
List fruitsList = new ArrayList<>();
Collections.addAll(fruitsList,fruits.split(","));
//Such operation will be simplified like below
String fruitsTextBlocks = """
        Apple
        Orange
        Banana
        """;
List lisOfFruits = fruitsTextBlocks.lines().collect(Collectors.toList());

Этапы компиляции

Текстовый блок обрабатывается компилятором в три этапа:

  1. Терминатор строки — Windows и Linux имеют разное окончание строки, Windows использует возврат каретки и перевод строки (“\r\n”), а Linux использует только перевод строки (“\n”). Чтобы избежать каких-либо проблем при переносе исходного кода из одной ОС в другую, текстовые блоки нормализуют окончание строки на \u000a. Экранирующие последовательности \n (LF), \f (FF) и \r (CR) не интерпретируются во время нормализации; экранирующая обработка выполняется позже.

  2. Удалить случайные пробелы — Вышеуказанные шаги выполняют нормализацию, на этих шагах все случайные пробелы будут удалены, как описано выше. Escape-последовательности \b (backspace) и \t (tab) не интерпретируются алгоритмом; обработка escape происходит позже.

  3. Интерпретировать escape-последовательность — Если ваш текстовый блок имеет какую-либо экранирующую последовательность, теперь он будет интерпретирован. Текстовые блоки поддерживают все escape-последовательности, поддерживаемые строковыми литералами, включая \n, \t, \’, \” и \.

Escape-последовательность

  • Обработка escape-последовательности “

Вполне допустимо иметь escape-последовательность ” в текстовом блоке, см. Ниже

  String textBlockWithES = """
      When your "work" speaks for yourself don't Interrupt
      """;  

но если вы пытаетесь поместить его рядом с закрывающим разделителем, как показано ниже:

  String textBlockWithESI = """
      When your "work" speaks for yourself don't "Interrupt"""";

Это будет ошибка времени компиляции, ее можно решить двумя способами:

  1. Перенесите закрывающий разделитель на следующую строку.

  2. Используйте escape

  String textBlockWithESI = """
      When your "work" speaks for yourself don't "Interrupt\"""";

Этот экранирующий символ \ может быть помещен перед любым ” из последних четырех (“”””) в строке выше.

  • Текстовый блок может быть встроен в другой текстовый блок – если вы пытаетесь поместить тройное “”” в текстовый блок в любом месте, кроме открывающего и закрывающего разделителя, вы вставили escape-символ, иначе это будет ошибка времени компиляции:
  String textBlockWithESII = """
      When your "work" \""" speaks for yourself don't "Interrupt\"""";
  //Above is a valid Text Block 

На аналогичной линии если вам нужно вставить другой текстовый блок внутри текстового блока, вы должны использовать escape-символ

  String textBlockWithAnotherEmbedded =
          """
          String text = \"""
              A text block inside a text block
          ""\";
          """;

### Новые Escape-Последовательности

  1. Это очень распространенная практика/требование, когда длинная строка, разделенная на несколько подстрок, объединяет их с помощью ‘+’ для поддержания удобочитаемости кода, но вывод будет представлять собой одну строку. Для обработки аналогичного требования новая escape-последовательность \ добавлена в java, это будет работать только с текстовыми блоками.
  String quoteAsStr = "Fearlessness is like a muscle. " +
          "I know from my own life that the more I exercise it, " +
          "the more natural it becomes to not let my fears run me.";

  System.out.println(quoteAsStr);
  String quoteAsTextBlocks = """
          Fearlessness is like a muscle. \
          I know from my own life that the more I exercise it, \
          the more natural it becomes to not let my fears run me.""";
  System.out.println(quoteAsTextBlocks);

если вы выполните приведенный выше код, оба вывода на печать будут точно такими же

  Fearlessness is like a muscle. I know from my own life that the more I exercise it, the more natural it becomes to not let my fears run me.

  Fearlessness is like a muscle. I know from my own life that the more I exercise it, the more natural it becomes to not let my fears run me.
  1. Еще одна новая escape-последовательность \s , добавленная с помощью этого JEP, заключается в Escape-последовательности не переводятся до тех пор, пока не будет удален пробел инцидента, поэтому \s может выступать в качестве ограждения для предотвращения удаления завершающего пробела. Эта экранирующая последовательность применима как к строковым, так и к текстовым блокам.
  String colors = """
          red  \s""";
  System.out.println(colors.length());

на выходе консоли будет 6.

Новые Методы

  • Строка::отступ полосы()

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

  String fruitsStr = "red\n   green\n   blue";
  System.out.println(fruitsStr);
  //1- It will print 
  //red
  //   green
  //   blue
  System.out.println(fruitsStr.replace(" ","."));
  //2- It will print
  //red
  //...green
  //...blue
  System.out.println(fruitsStr.stripIndent());
  //3- It will print
  //red
  //   green
  //   blue

В приведенном выше фрагменте вы можете заметить, что метод stripIndent() не влияет, поскольку компилятор не находит случайных пробелов, но если у вас есть строка, подобная приведенной ниже:

  String fruitsStrWithLeadingSpace = "  red\n   green\n   blue";
  System.out.println(fruitsStrWithLeadingSpace);
  //1- It will print
  //  red
  //   green
  //   blue
  System.out.println(fruitsStrWithLeadingSpace.replace(" ","."));
  //2- It will print
  //..red
  //...green
  //...blue
  System.out.println(fruitsStrWithLeadingSpace.stripIndent());
  //3- It will print
  //red
  // green
  // blue

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

  • Строка::перевод Экранирует()

Как следует из названия, это переведет escape-последовательность, присутствующую в строке, см. Пример ниже

  String fruitsStr = "red\n   green\\n   \"blue\"";
  System.out.println(fruitsStr);
  //1- It will print
  //red
  //   green\n   "blue"
  System.out.println(fruitsStr.translateEscapes());
  //2- And after translateEscape, it will print
  //red
  //   green
  //   "blue"

вы можете заметить, что символ новой строки был переведен в 2- консольная печать.

  • Строка::отформатирована(объект… аргументы)
String jsonAsTextBlocks =  """
{
"name":"%s"
}
 """.formatted("Ashish");
System.out.println(jsonAsTextBlocks);
//It will print
//{
//"name":"Ashish"
//}

Это работает очень похоже на String.

Надеюсь, вам, ребята, это понравилось.

Оговорка

Он уже публиковался ранее на medium https://medium.com/analytics-vidhya/text-blocks-jep-368-56c1625f97cf

Оригинал: “https://dev.to/imagarg/textblocks-5fp”