C, PHP, VB, .NET

Дневникът на Филип Петров


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

Публикувано на 19 декември 2019 в раздел ПИК3 Java.

Един чест и досаден проблем за разработчиците на Java винаги е бил четимостта на кода. Един от няколкото основни фактора за лошо визуализиран код винаги са били многоредовите низове. Например ако искаме да подобрим четимостта на следната SQL заявка:

String sql = "SELECT title, contents FROM articles WHERE id=5";

Можем да я напишем на три реда по следния начин:

String sql = "SELECT title, contents "+
             "FROM articles "+
             "WHERE id=5";

или същото написано с поставяне на нов ред вместо понякога заблуждаващия интервал (ако интервалът бъде пропуснат, това няма да доведе до валидна заявка):

String sql = "SELECT title, contents\n"+
             "FROM articles\n"+
             "WHERE id=5";

И в двата случая имаме конкатениране на низове, т.е. значително количество кавички и знак „+“, както и неприятна грижа за разделителите в края на всеки ред. В Java до този момент няма възможност за многоредови низове, тоест нещо подобно на следното (поне към JDK13) НЕ е възможно:

String sql = "SELECT title, contents
              FROM articles
              WHERE id=5";

защото ще даде грешка „Unclosed String Literal“ на всеки ред. Но дори да беше възможно, отново ще е лошо решение, защото добавяме ненужни интервали в началото на втори и трети ред, които удължават ненужно дължината на текстовия низ (при друг вид код или текст тези празни интервали може да са нежелани).

Още по-лошо – ако в кода трябва да има кавички, тогава става още по-неприятно за четене:

String sql = "SELECT id, user\n"+
             "FROM users\n"+
             "WHERE fname=\"Ivan\"\n"+
             "AND lname=\"Ivanov\"";

В JDK13 е пуснато preview (за тестване – все още неперманентно) разширение на езика, с което тези проблеми биха могли да бъдат оправени. Чрез оператор „три двойни кавички“ се дефинира начало и край на „текстови блок“. Така горният пример ще може да се напише по следния начин:

String sql = """
             SELECT id, user
             FROM users
             WHERE fname="Ivan"
               AND lname="Ivanov"
             """;

Така не се грижим за нови редове, конкатенация и слагането на \ преди кавичките. Освен това празните интервали в началото на всеки ред НЕ са част от текстовия низ. Всъщност от началото на всеки ред се премахват толкова интервала, колкото има на последния ред до затварящите „тройни двойни кавички“. Тоест последният пример ще произведе следното съдържание на текстовия низ sql (забележете, че два празни интервала преди AND се запазват – изрязват в случая се само първите 13 интервала от всеки ред!):

SELECT id, user
FROM users
WHERE fname="Ivan"
  AND lname="Ivanov"

Докато например следното:

String sql = """
             SELECT id, user
             FROM users
             WHERE fname="Ivan"
               AND lname="Ivanov"
         """;

ще направи четири празни интервала в началото на всеки ред (защото затварящите „““ са дръпнати с четири интервала наляво, т.е. вече изрязваме само 13-4=9 празни интервала от началото на всеки ред):

    SELECT id, user
    FROM users
    WHERE fname="Ivan"
      AND lname="Ivanov"

Ако затварянето на блока е дръпнато надясно спрямо текста в блока, това няма да има значение – ще се приеме, че все едно е поставен в началото му (първа колона на текстовия блок).

Тук трябва да внесем едно дребно уточнение, което на този етап е дискусионно: така дефинирани, в края на всеки низ има по един празен нов ред. Тоест:

String str = """
             text
             """;

Всъщност ще е еквивалентно на:

String str = "text\n";

Ако НЕ желаете този нов ред да стои в текста, може да затваряте блока в края на горния ред:

String str = """
             text""";

Това може да се убедите сами може би не е най-добре изглеждащото решение. Едно по-добро може би е следното:

String str = """
             text
             """.strip();

Функциите strip (подобрен UTF8 съвместим еквивалент на trim), stripLeading (премахва празни символи само в началото) и strilTrailing (премахва празни символи само в края) са нововъведения в Java11.

Друго нещо, което трябва да знаете, е че може (и понякога все пак трябва) да използвате добре познатите escape символи като \n, \t, \’, \“, и \\. Въпреки, че от тях само \\ е задължително нужен, понякога може да се наложат и другите. Например ако искате да изобразите тройни кавички, ще се наложи поне една от тях да има наклонена черта в началото:

String str = """
             В JDK13 има оператор \"""
          """.stripTrailing();

Последното е еквивалентно на:

String str = "   В JDK13 има оператор \"\"\"";

Дали текстовите блокове ще бъдат приети като перманентно въведение в езика все още не е ясно, но е нещо, което заслужава да бъде пробвано.

Обновено 19.03.2020 г.

С JDK14 се добавиха две нововъведения. Първото е свързано с нуждата от евентуално запазване на празните символи в края на всеки ред. Това се случва с добавяне на \s:

String str = """
             abc    \s
             abcdef \s
             a      \s
             """.strip();

По този начин str ще е със съдържание „abc    \nabcdef \na      „, т.е. интервалите в края на всеки ред са запазени.

Друго нововъведение е свързано с премахването на нов ред. Това се случва с поставяне само на \ в края на реда. Така например:

String str = """
             Philip \
             Petrov \
             """;

Ще бъде произведе низ „Philip Petrov“. Това ще се прави предимно в случаите, когато трябва да се конкатенират много дълги низове. Допълнителен плюс е, че дава значително по-елегантен начин за премахване на последния празен ред, както беше описано по-горе при JDK13. Вече вместо:

String str = """
             Line 1
             Line 2
             """.strip();

може да се прави:

String str = """
             Line 1
             Line 2\
             """

Забележете, че при използване на тази техника празните интервали преди \ се запазват.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*